` 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/CONTRIBUTING.md b/CONTRIBUTING.md
index 43ee0636d3..ac262a0f34 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, 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!
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
diff --git a/README.md b/README.md
index f1d1d6ee0b..e080d32da8 100644
--- a/README.md
+++ b/README.md
@@ -1,23 +1,15 @@
# 
-Master:
-[](https://packagist.org/packages/phpoffice/phpword)
-[](https://travis-ci.org/PHPOffice/PHPWord)
-[](https://scrutinizer-ci.com/g/PHPOffice/PHPWord/)
+[](https://packagist.org/packages/phpoffice/phpword)
[](https://coveralls.io/github/PHPOffice/PHPWord?branch=master)
-[](https://packagist.org/packages/phpoffice/phpword)
-[](https://packagist.org/packages/phpoffice/phpword)
-[](https://gitter.im/PHPOffice/PHPWord)
+[](https://packagist.org/packages/phpoffice/phpword)
+[](https://packagist.org/packages/phpoffice/phpword)
-Develop:
-[](https://packagist.org/packages/phpoffice/phpword#dev-develop)
-[](https://travis-ci.org/PHPOffice/PHPWord/branches)
-[](https://scrutinizer-ci.com/g/PHPOffice/PHPWord/?branch=develop)
-[](https://coveralls.io/github/PHPOffice/PHPWord?branch=develop)
+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.
-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://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)
@@ -28,11 +20,11 @@ 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
-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,10 +52,9 @@ With PHPWord, you can create OOXML, ODF, or RTF documents dynamically using your
PHPWord requires the following:
-- PHP 5.3.3+
+- PHP 7.1+
- [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)
@@ -73,24 +64,15 @@ 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
- composer require phpoffice/phpword
+composer require phpoffice/phpword
```
-or if you want the latest master version
+or if you want the latest unreleased version
```sh
- composer require phpoffice/phpword:dev-master
-```
-
-You can of course also manually edit your composer.json file
-```json
-{
- "require": {
- "phpoffice/phpword": "v0.16.*"
- }
-}
+composer require phpoffice/phpword:dev-master
```
## Getting started
@@ -99,7 +81,6 @@ The following is a basic usage example of the PHPWord library.
```php
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
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.
+- 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/bootstrap.php b/bootstrap.php
deleted file mode 100644
index 740e3d044c..0000000000
--- a/bootstrap.php
+++ /dev/null
@@ -1,28 +0,0 @@
-=7.0",
+ "symfony/process": "^4.4 || ^5.0",
+ "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"
@@ -88,9 +136,9 @@
"PhpOffice\\PhpWord\\": "src/PhpWord"
}
},
- "extra": {
- "branch-alias": {
- "dev-develop": "0.17-dev"
+ "autoload-dev": {
+ "psr-4": {
+ "PhpOffice\\PhpWordTests\\": "tests/PhpWordTests"
}
}
}
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
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/PULL_REQUEST_TEMPLATE.md b/docs/PULL_REQUEST_TEMPLATE.md
deleted file mode 100644
index 5430a996ec..0000000000
--- a/docs/PULL_REQUEST_TEMPLATE.md
+++ /dev/null
@@ -1,11 +0,0 @@
-### 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 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
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..7a4b09ea2d
--- /dev/null
+++ b/docs/changes/1.x/1.2.0.md
@@ -0,0 +1,68 @@
+# [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)
+
+## 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
+- 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)
+- 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
+- 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
+
+- 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
+- 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
+
+- 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
+- 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)
+- 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)
+- 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`
+- *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/1.x/1.3.0.md b/docs/changes/1.x/1.3.0.md
new file mode 100644
index 0000000000..4b2e1b25df
--- /dev/null
+++ b/docs/changes/1.x/1.3.0.md
@@ -0,0 +1,53 @@
+# [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)
+
+## 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)
+- 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)
+- 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
+
+- 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)
+- 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)
+- 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)
+- 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
+
+- 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)
+- 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 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)
+- 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/docs/changes/1.x/1.4.0.md b/docs/changes/1.x/1.4.0.md
new file mode 100644
index 0000000000..5daf85dbfd
--- /dev/null
+++ b/docs/changes/1.x/1.4.0.md
@@ -0,0 +1,56 @@
+# [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)
+
+## 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)
+- 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)
+- 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)
+- 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)
+- 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
+
+- 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 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)
+- Enhanced error handling in encoding functions [@michalschroeder](https://github.com/michalschroeder) in [#2784](https://github.com/PHPOffice/PHPWord/pull/2784)
+
+### 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)
+- 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()`
+- 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
+
+### 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/docs/changes/1.x/1.5.0.md b/docs/changes/1.x/1.5.0.md
new file mode 100644
index 0000000000..b96865bada
--- /dev/null
+++ b/docs/changes/1.x/1.5.0.md
@@ -0,0 +1,19 @@
+# [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
+
+- 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
+
+- 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
+
+### Notes
\ No newline at end of file
diff --git a/docs/conf.py b/docs/conf.py
deleted file mode 100644
index d83c43f583..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-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.16.0'
-# 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_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.
-
-.. 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 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
-----------
-
-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])
-
-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 19fca1057f..0000000000
--- a/docs/faq.rst
+++ /dev/null
@@ -1,24 +0,0 @@
-.. _faq:
-
-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/general.rst b/docs/general.rst
deleted file mode 100644
index f40a08c367..0000000000
--- a/docs/general.rst
+++ /dev/null
@@ -1,334 +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 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 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->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\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
---------------------
-
-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..fd4c860682
--- /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(__DIR__ . '/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..211fc31a79
--- /dev/null
+++ b/docs/index.md
@@ -0,0 +1,115 @@
+#
+
+
+
+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: | :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 | :material-check: | | | | |
+| | MathML support | | :material-check: | | | |
+| **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 | :material-check: | | | | |
+| **Graphs** | 2D basic graphs | | | | | |
+| | 2D advanced graphs | | | | | |
+| | 3D graphs | | | | | |
+| **Math** | OMML support | :material-check: | | | | |
+| | MathML support | | :material-check: | | | |
+| **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..4e485bf739
--- /dev/null
+++ b/docs/install.md
@@ -0,0 +1,70 @@
+# 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)
+* extract the package and put the contents to your machine.
+
+
+``` php
+`__ extension
-- `Zend\\Escaper `__ component
-- Zend\\Stdlib component
-- `Zend\\Validator `__ component
-
-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:: json
-
- {
- "require": {
- "phpoffice/phpword": "v0.14.*"
- }
- }
-
-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
-
- {
- "require": {
- "phpoffice/phpword": "dev-develop"
- }
- }
-
-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 d88cd626dd..0000000000
--- a/docs/intro.rst
+++ /dev/null
@@ -1,199 +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 by incorporating
-`continuous integration `__ and
-`unit testing `__.
-You can learn more about PHPWord by reading this Developers'
-Documentation and the `API
-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
- `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
deleted file mode 100644
index 5042cdedc6..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->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.
-
-.. 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 27f8ee66ce..0000000000
--- a/docs/styles.rst
+++ /dev/null
@@ -1,209 +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 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 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*.
-- ``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*.
-- ``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 5b32aa18e0..0000000000
--- a/docs/templates-processing.rst
+++ /dev/null
@@ -1,246 +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.
-Macros are defined like this: ``${search-pattern}``.
-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'));
-
-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));
-
-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', );
-
-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
-"""""""""""""""
-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);
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..50813fa2a1
--- /dev/null
+++ b/docs/usage/elements/comment.md
@@ -0,0 +1,24 @@
+# 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 ``setCommentRangeStart``.
+
+``` 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->setCommentRangeStart($comment);
+$textrun->addText(' a test');
+```
+
+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
diff --git a/docs/usage/elements/field.md b/docs/usage/elements/field.md
new file mode 100644
index 0000000000..1cafd18ef8
--- /dev/null
+++ b/docs/usage/elements/field.md
@@ -0,0 +1,49 @@
+# Field
+
+Currently the following fields are supported:
+
+- PAGE
+- NUMPAGES
+- DATE
+- XE
+- INDEX
+- FILENAME
+- REF
+
+``` 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');
+
+// Adding reference to a bookmark
+$fieldText->addField('REF', [
+ 'name' => 'bookmark'
+], [
+ 'InsertParagraphNumberRelativeContext',
+ 'CreateHyperLink',
+]);
+```
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/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/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
+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/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..fba78ef645
--- /dev/null
+++ b/docs/usage/elements/title.md
@@ -0,0 +1,24 @@
+# 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, $pageNumber);
+```
+
+`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/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..19d6aff51f
--- /dev/null
+++ b/docs/usage/introduction.md
@@ -0,0 +1,392 @@
+# 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->setDefaultFontColor('FF0000');
+$phpWord->setDefaultFontSize(12);
+```
+
+Or you can specify Asian Font
+
+``` php
+setDefaultAsianFontName('標楷體');
+```
+
+## 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);
+```
+
+!!! 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.
+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);
+```
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..921dc7fd85
--- /dev/null
+++ b/docs/usage/styles/font.md
@@ -0,0 +1,28 @@
+# 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*.
+- ``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/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..f51d5ba030
--- /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*, *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*.
+- ``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..a0c885e75e
--- /dev/null
+++ b/docs/usage/template.md
@@ -0,0 +1,372 @@
+# 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'));
+```
+
+## 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.
+
+``` 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..97708a0294
--- /dev/null
+++ b/docs/usage/writers.md
@@ -0,0 +1,152 @@
+# Writers
+
+## HTML
+The name of the writer is `HTML`.
+
+``` php
+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
+$writer = IOFactory::createWriter($oPhpWord, 'HTML');
+$writer->setDefaultGenericFont('serif');
+$writer->setDefaultWhiteSpace('pre-wrap');
+$writer->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');
+```
+
+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 :
+* `font`: default font
+
+Options must be defined before creating the writer.
+
+``` php
+ 'Arial'
+]);
+
+$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');
+```
+
+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`.
+
+``` 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..97c842112c
--- /dev/null
+++ b/mkdocs.yml
@@ -0,0 +1,121 @@
+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'
+ - Formula: 'usage/elements/formula.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'
+ - Ruby: 'usage/elements/ruby.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.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'
+ - '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/phpmd.xml.dist b/phpmd.xml.dist
index 44b3efdf66..aeb2774881 100644
--- a/phpmd.xml.dist
+++ b/phpmd.xml.dist
@@ -5,6 +5,8 @@
xsi:schemaLocation="http://pmd.sf.net/ruleset/1.0.0 http://pmd.sf.net/ruleset_xml_schema.xsd"
xsi:noNamespaceSchemaLocation="http://pmd.sf.net/ruleset_xml_schema.xsd">
+
+
@@ -17,9 +19,9 @@
-
+
-
+
@@ -28,6 +30,5 @@
-
\ No newline at end of file
diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon
new file mode 100644
index 0000000000..ea75a4bd91
--- /dev/null
+++ b/phpstan-baseline.neon
@@ -0,0 +1,1877 @@
+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: "#^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: "#^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: "#^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: "#^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: "#^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: "#^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\\:\\: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
+ 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: 3
+ 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\\\\XMLWriter\\:\\:getData\\(\\) should return string but returns 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: "#^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\\\\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: "#^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: "#^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: "#^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 \\#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\\:\\:\\$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: "#^Method PhpOffice\\\\PhpWord\\\\Writer\\\\HTML\\\\Element\\\\AbstractElement\\:\\:write\\(\\) has no return type specified\\.$#"
+ count: 1
+ path: src/PhpWord/Writer/HTML/Element/AbstractElement.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: "#^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\\\\AbstractElement\\:\\:replaceTabs\\(\\) has parameter \\$text with no type specified\\.$#"
+ count: 1
+ path: src/PhpWord/Writer/ODText/Element/AbstractElement.php
+
+ -
+ message: "#^Method PhpOffice\\\\PhpWord\\\\Writer\\\\ODText\\\\Element\\\\AbstractElement\\:\\:replaceTabs\\(\\) has parameter \\$xmlWriter with no type specified\\.$#"
+ count: 1
+ path: src/PhpWord/Writer/ODText/Element/AbstractElement.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: "#^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: "#^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: "#^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: "#^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: "#^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: "#^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\\\\AbstractWebServerEmbedded\\:\\:getBaseUrl\\(\\) has no return type specified\\.$#"
+ count: 1
+ path: tests/PhpWordTests/AbstractWebServerEmbedded.php
+
+ -
+ message: "#^Method PhpOffice\\\\PhpWordTests\\\\AbstractWebServerEmbedded\\:\\:getRemoteBmpImageUrl\\(\\) has no return type specified\\.$#"
+ count: 1
+ path: tests/PhpWordTests/AbstractWebServerEmbedded.php
+
+ -
+ message: "#^Method PhpOffice\\\\PhpWordTests\\\\AbstractWebServerEmbedded\\:\\:getRemoteGifImageUrl\\(\\) has no return type specified\\.$#"
+ count: 1
+ path: tests/PhpWordTests/AbstractWebServerEmbedded.php
+
+ -
+ message: "#^Method PhpOffice\\\\PhpWordTests\\\\AbstractWebServerEmbedded\\:\\:getRemoteImageUrl\\(\\) has no return type specified\\.$#"
+ count: 1
+ path: tests/PhpWordTests/AbstractWebServerEmbedded.php
+
+ -
+ message: "#^Property PhpOffice\\\\PhpWordTests\\\\AbstractWebServerEmbedded\\:\\:\\$httpServer has no type specified\\.$#"
+ count: 1
+ path: tests/PhpWordTests/AbstractWebServerEmbedded.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\\:\\: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: "#^Cannot call method setLineHeight\\(\\) on PhpOffice\\\\PhpWord\\\\Style\\\\Paragraph\\|string\\.$#"
+ 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: "#^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: "#^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: 9
+ path: tests/PhpWordTests/Writer/HTML/ElementTest.php
+
+ -
+ message: "#^Cannot access property \\$length on DOMNodeList\\\\|false\\.$#"
+ count: 2
+ path: tests/PhpWordTests/Writer/HTML/Element/RubyTest.php
+
+ -
+ message: "#^Cannot call method item\\(\\) on DOMNodeList\\\\|false\\.$#"
+ count: 11
+ 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
+ path: tests/PhpWordTests/Writer/ODText/Style/FontTest.php
+
+ -
+ message: "#^Call to an undefined method PhpOffice\\\\PhpWord\\\\Writer\\\\PDF\\:\\:getFont\\(\\)\\.$#"
+ count: 2
+ 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\\:\\: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: 3
+ path: tests/PhpWordTests/Writer/PDF/DomPDFTest.php
+
+ -
+ message: "#^Call to an undefined method PhpOffice\\\\PhpWord\\\\Writer\\\\PDF\\:\\:getFont\\(\\)\\.$#"
+ 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
+ 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
+
+ -
+ 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
+
+ # 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 b/phpstan.neon
deleted file mode 100644
index 666c63b9c1..0000000000
--- a/phpstan.neon
+++ /dev/null
@@ -1,13 +0,0 @@
-includes:
- - vendor/phpstan/phpstan/conf/config.level1.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
diff --git a/phpstan.neon.dist b/phpstan.neon.dist
new file mode 100644
index 0000000000..cf26b6956b
--- /dev/null
+++ b/phpstan.neon.dist
@@ -0,0 +1,45 @@
+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
+ treatPhpDocTypesAsCertain: false
+ ignoreErrors:
+ -
+ identifier: missingType.iterableValue
+
+ ## <=PHP7.4
+ -
+ message: '#Parameter \#1 \$argument of class ReflectionClass constructor expects class-string\|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, 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, class-string\|false given.#'
+ path: tests/PhpWordTests/Style/AbstractStyleTest.php
diff --git a/phpunit.xml.dist b/phpunit.xml.dist
index 4a8824468e..6f1f5445ab 100644
--- a/phpunit.xml.dist
+++ b/phpunit.xml.dist
@@ -1,28 +1,24 @@
-
-
-
- ./tests/PhpWord
-
-
-
-
- ./src
-
- ./src/PhpWord/Shared/PCLZip
-
-
-
-
-
-
-
-
-
\ No newline at end of file
+
+
+
+
+ ./src
+
+
+ ./src/PhpWord/Shared/PCLZip
+
+
+
+
+
+
+
+
+
+
+
+ ./tests/PhpWordTests
+
+
+
+
diff --git a/phpword.ini.dist b/phpword.ini.dist
index 0f4cc358df..21d3b50609 100644
--- a/phpword.ini.dist
+++ b/phpword.ini.dist
@@ -14,3 +14,8 @@ outputEscapingEnabled = false
defaultFontName = Arial
defaultFontSize = 10
+defaultFontColor = 000000
+
+[Paper]
+
+defaultPaper = "A4"
diff --git a/samples/Sample_01_SimpleText.php b/samples/Sample_01_SimpleText.php
index 8af44d20aa..07e0d05aa5 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(__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 4f588ee7b8..ad99fe83f5 100644
--- a/samples/Sample_02_TabStops.php
+++ b/samples/Sample_02_TabStops.php
@@ -1,28 +1,29 @@
addParagraphStyle(
$multipleTabsStyleName,
- array(
- 'tabs' => array(
- new \PhpOffice\PhpWord\Style\Tab('left', 1550),
- new \PhpOffice\PhpWord\Style\Tab('center', 3200),
- new \PhpOffice\PhpWord\Style\Tab('right', 5300),
- ),
- )
+ [
+ '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..b01726d81c 100644
--- a/samples/Sample_03_Sections.php
+++ b/samples/Sample_03_Sections.php
@@ -1,44 +1,45 @@
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..6d50e285ec 100644
--- a/samples/Sample_04_Textrun.php
+++ b/samples/Sample_04_Textrun.php
@@ -1,22 +1,23 @@
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(__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();
-$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..c4d1dd7280 100644
--- a/samples/Sample_05_Multicolumn.php
+++ b/samples/Sample_05_Multicolumn.php
@@ -1,9 +1,10 @@
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..035916ee09 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,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', array('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 42c53269e8..0f1d165f19 100644
--- a/samples/Sample_07_TemplateCloneRow.php
+++ b/samples/Sample_07_TemplateCloneRow.php
@@ -1,9 +1,10 @@
setValue('weekday', date('l')); // On section/content
@@ -36,26 +37,26 @@
$templateProcessor->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);
@@ -78,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(array('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 3c21b138fc..cac52e3baf 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,
- 'spaceAfter' => \PhpOffice\PhpWord\Shared\Converter::pointToTwip(12),
- 'spacing' => 120,
- )
+ [
+ 'alignment' => PhpOffice\PhpWord\SimpleType\Jc::BOTH,
+ 'spaceAfter' => PhpOffice\PhpWord\Shared\Converter::pointToTwip(12),
+ '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 32d895732d..3a887468b0 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 <= 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}");
}
}
@@ -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}");
@@ -55,46 +56,43 @@
/*
* 3. colspan (gridSpan) and rowspan (vMerge)
- * ---------------------
- * | | B | |
- * | A |--------| E |
- * | | C | D | |
- * ---------------------
+ * -------------------------
+ * | A | B | C |
+ * |-----|-----------| |
+ * | D | |
+ * ------|-----------| |
+ * | E | F | G | |
+ * -------------------------
*/
$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);
$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)
@@ -111,22 +109,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 +134,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 +145,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..f730ab510f 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..72cdfac625 100644
--- a/samples/Sample_11_ReadWord2007.php
+++ b/samples/Sample_11_ReadWord2007.php
@@ -1,4 +1,5 @@
addSection();
@@ -17,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', array('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', array('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, 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..a8ab87ce8c 100644
--- a/samples/Sample_13_Images.php
+++ b/samples/Sample_13_Images.php
@@ -1,21 +1,23 @@
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', array('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);
@@ -25,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);
@@ -33,21 +35,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),
+ __DIR__ . '/resources/_earth.jpg',
+ [
+ '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);
@@ -56,17 +58,17 @@
//Absolute positioning
$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,
- '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),
- )
+ __DIR__ . '/resources/_mars.jpg',
+ [
+ '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),
+ ]
);
//Relative positioning
@@ -74,22 +76,22 @@
$section->addText('Relative positioning: Horizontal position center relative to column,');
$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,
- '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,
- )
+ __DIR__ . '/resources/_mars.jpg',
+ [
+ '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,
+ ]
);
-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..f82c3ec064 100644
--- a/samples/Sample_14_ListItem.php
+++ b/samples/Sample_14_ListItem.php
@@ -1,30 +1,31 @@
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..43994deaa2 100644
--- a/samples/Sample_15_Link.php
+++ b/samples/Sample_15_Link.php
@@ -1,13 +1,14 @@
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..d3912a6c50 100644
--- a/samples/Sample_16_Object.php
+++ b/samples/Sample_16_Object.php
@@ -1,15 +1,16 @@
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 86e8e28cf7..3102ebda83 100644
--- a/samples/Sample_17_TitleTOC.php
+++ b/samples/Sample_17_TitleTOC.php
@@ -1,22 +1,23 @@
getSettings()->setUpdateFields(true);
// New section
$section = $phpWord->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..0b3ae34f83 100644
--- a/samples/Sample_18_Watermark.php
+++ b/samples/Sample_18_Watermark.php
@@ -1,14 +1,15 @@
addSection();
$header = $section->addHeader();
-$header->addWatermark('resources/_earth.jpg', array('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 17e2b1cbd7..0b41110b18 100644
--- a/samples/Sample_19_TextBreak.php
+++ b/samples/Sample_19_TextBreak.php
@@ -1,20 +1,21 @@
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..e0ce4d6436 100644
--- a/samples/Sample_20_BGColor.php
+++ b/samples/Sample_20_BGColor.php
@@ -1,19 +1,20 @@
addSection();
$section->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..0ddaa08faf 100644
--- a/samples/Sample_21_TableRowRules.php
+++ b/samples/Sample_21_TableRowRules.php
@@ -1,9 +1,10 @@
addSection();
@@ -15,25 +16,25 @@
. 'the textbreak is still there:'
);
-$table1 = $section->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(__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:");
$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(__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 5a2ac3e2cc..91685924b0 100644
--- a/samples/Sample_22_CheckBox.php
+++ b/samples/Sample_22_CheckBox.php
@@ -1,9 +1,10 @@
addSection();
diff --git a/samples/Sample_23_TemplateBlock.php b/samples/Sample_23_TemplateBlock.php
index c0123f9283..4cc541ab3a 100644
--- a/samples/Sample_23_TemplateBlock.php
+++ b/samples/Sample_23_TemplateBlock.php
@@ -1,9 +1,10 @@
cloneBlock('CLONEME', 3);
@@ -12,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(array('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 42df23ae2b..1b3a43cd57 100644
--- a/samples/Sample_24_ReadODText.php
+++ b/samples/Sample_24_ReadODText.php
@@ -1,4 +1,5 @@
addSection();
// In section
$textbox = $section->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(__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 6bd926fe5b..971c317c43 100644
--- a/samples/Sample_26_Html.php
+++ b/samples/Sample_26_Html.php
@@ -1,17 +1,18 @@
addParagraphStyle('Heading2', array('alignment' => 'center'));
+$phpWord = new PhpOffice\PhpWord\PhpWord();
+$phpWord->addParagraphStyle('Heading2', ['alignment' => 'center']);
$section = $phpWord->addSection();
$html = 'Adding element via HTML ';
$html .= 'Some well-formed HTML snippet needs to be used
';
$html .= 'With for example some1 inline formatting 1
';
-$html .= 'A link to Read the docs
';
+$html .= 'A link to Read the docs
';
$html .= 'היי, זה פסקה מימין לשמאל
';
@@ -92,7 +93,7 @@
$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);
+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 4e7a5b2264..e1dbb4f258 100644
--- a/samples/Sample_27_Field.php
+++ b/samples/Sample_27_Field.php
@@ -1,12 +1,13 @@
14));
+$phpWord = new PhpOffice\PhpWord\PhpWord();
+PhpOffice\PhpWord\Style::addTitleStyle(1, ['size' => 14]);
// New section
$section = $phpWord->addSection();
@@ -15,53 +16,56 @@
// 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->addText('Filename field:');
+$section->addField('FILENAME', ['format' => 'Upper'], ['Path', '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..52aa74a9a5 100644
--- a/samples/Sample_28_ReadRTF.php
+++ b/samples/Sample_28_ReadRTF.php
@@ -1,4 +1,5 @@
addSection();
@@ -12,49 +13,49 @@
// See Element/Line.php for all options
$section->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..b6564eddc8 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 c24a6f8e37..c8c65e989e 100644
--- a/samples/Sample_32_Chart.php
+++ b/samples/Sample_32_Chart.php
@@ -1,30 +1,34 @@
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;
+$legendPosition = 't';
+// r = right, l = left, t = top, b = bottom, tr = top right
foreach ($chartTypes as $chartType) {
$section->addTitle(ucfirst($chartType), 2);
@@ -33,6 +37,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);
}
@@ -43,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..223fdd2987 100644
--- a/samples/Sample_33_FormField.php
+++ b/samples/Sample_33_FormField.php
@@ -1,10 +1,11 @@
getProtection()->setEditing('forms');
+$phpWord = new PhpOffice\PhpWord\PhpWord();
+$phpWord->getSettings()->getDocumentProtection()->setEditing('forms');
// New section
$section = $phpWord->addSection();
@@ -15,7 +16,7 @@
$textrun->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..4c8f588e81 100644
--- a/samples/Sample_34_SDT.php
+++ b/samples/Sample_34_SDT.php
@@ -1,16 +1,17 @@
addSection();
$textrun = $section->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..ef10c4b61f 100644
--- a/samples/Sample_35_InternalLink.php
+++ b/samples/Sample_35_InternalLink.php
@@ -1,9 +1,10 @@
addSection();
$section->addTitle('This is page 1', 1);
diff --git a/samples/Sample_36_RTL.php b/samples/Sample_36_RTL.php
index ca93b14df3..e3cf84576a 100644
--- a/samples/Sample_36_RTL.php
+++ b/samples/Sample_36_RTL.php
@@ -1,9 +1,16 @@
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();
@@ -11,29 +18,29 @@
$textrun = $section->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\SimpleType\VerticalJc::CENTER];
//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_37_Comments.php b/samples/Sample_37_Comments.php
index 268739bc67..ac03a699e4 100644
--- a/samples/Sample_37_Comments.php
+++ b/samples/Sample_37_Comments.php
@@ -1,13 +1,14 @@
addText('Test', array('bold' => true));
+$comment = new PhpOffice\PhpWord\Element\Comment('Authors name', new DateTime(), 'my_initials');
+$comment->addText('Test', ['bold' => true]);
$phpWord->addComment($comment);
$section = $phpWord->addSection();
@@ -21,27 +22,27 @@
$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);
$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);
$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'));
+$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);
@@ -49,12 +50,27 @@
// 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 = new PhpOffice\PhpWord\Element\Comment('Authors name', new DateTime(), 'my_initials');
+$comment1->addText('Test', ['bold' => true]);
$comment1->setStartElement($anotherText);
$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/samples/Sample_38_Protection.php b/samples/Sample_38_Protection.php
index ee2b460b2f..737946d51a 100644
--- a/samples/Sample_38_Protection.php
+++ b/samples/Sample_38_Protection.php
@@ -1,11 +1,12 @@
getSettings()->getDocumentProtection();
$documentProtection->setEditing(DocProtect::READ_ONLY);
diff --git a/samples/Sample_39_TrackChanges.php b/samples/Sample_39_TrackChanges.php
index e6a3066864..a2c2bcf61c 100644
--- a/samples/Sample_39_TrackChanges.php
+++ b/samples/Sample_39_TrackChanges.php
@@ -1,11 +1,12 @@
addSection();
@@ -13,14 +14,14 @@
$text = $textRun->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');
$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 094823f784..41cbab8950 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,16 +31,16 @@
$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');
// $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(array('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
new file mode 100644
index 0000000000..36be5888f7
--- /dev/null
+++ b/samples/Sample_41_TemplateSetChart.php
@@ -0,0 +1,46 @@
+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(__DIR__ . '/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_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_43_RTLDefault.php b/samples/Sample_43_RTLDefault.php
new file mode 100644
index 0000000000..164ddd4379
--- /dev/null
+++ b/samples/Sample_43_RTLDefault.php
@@ -0,0 +1,33 @@
+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';
+}
+Settings::setDefaultRtl(false);
diff --git a/samples/Sample_44_ExtractVariablesFromReaderWord2007.php b/samples/Sample_44_ExtractVariablesFromReaderWord2007.php
new file mode 100644
index 0000000000..8c1703499f
--- /dev/null
+++ b/samples/Sample_44_ExtractVariablesFromReaderWord2007.php
@@ -0,0 +1,14 @@
+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_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 @@
+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/samples/Sample_Header.php b/samples/Sample_Header.php
index f0fc626627..57bb10a4c6 100644
--- a/samples/Sample_Header.php
+++ b/samples/Sample_Header.php
@@ -1,5 +1,19 @@
'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()) {
@@ -43,7 +55,7 @@
// Populate samples
$files = '';
if ($handle = opendir('.')) {
- $sampleFiles = array();
+ $sampleFiles = [];
while (false !== ($sampleFile = readdir($handle))) {
$sampleFiles[] = $sampleFile;
}
@@ -59,15 +71,9 @@
}
/**
- * Write documents
- *
- * @param \PhpOffice\PhpWord\PhpWord $phpWord
- * @param string $filename
- * @param array $writers
- *
- * @return string
+ * Write documents.
*/
-function write($phpWord, $filename, $writers)
+function write(PhpOffice\PhpWord\PhpWord $phpWord, string $filename, array $writers): string
{
$result = '';
@@ -89,13 +95,9 @@ function write($phpWord, $filename, $writers)
}
/**
- * Get ending notes
- *
- * @param array $writers
- * @param mixed $filename
- * @return string
+ * Get ending notes.
*/
-function getEndingNotes($writers, $filename)
+function getEndingNotes(array $writers, string $filename): string
{
$result = '';
@@ -114,7 +116,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} ";
@@ -164,8 +166,8 @@ function getEndingNotes($writers, $filename)
diff --git a/samples/index.php b/samples/index.php
index 20b56b8317..a9733d2c7c 100644
--- a/samples/index.php
+++ b/samples/index.php
@@ -3,15 +3,15 @@
use PhpOffice\PhpWord\Settings;
-$requirements = array(
- 'php' => array('PHP 5.3.3', version_compare(PHP_VERSION, '5.3.3', '>=')),
- '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.1', version_compare(PHP_VERSION, '7.1', '>=')],
+ '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) {
?>
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/samples/resources/Sample_30_ReadHTML.html b/samples/resources/Sample_30_ReadHTML.html
index b4af381204..f9ce478c20 100644
--- a/samples/resources/Sample_30_ReadHTML.html
+++ b/samples/resources/Sample_30_ReadHTML.html
@@ -15,7 +15,7 @@ Adding element via HTML
Double height
Includes images
-
+
diff --git a/samples/resources/Sample_41_TemplateSetChart.docx b/samples/resources/Sample_41_TemplateSetChart.docx
new file mode 100644
index 0000000000..c958b335c8
Binary files /dev/null and b/samples/resources/Sample_41_TemplateSetChart.docx differ
diff --git a/samples/resources/Sample_42_TemplateSetCheckbox.docx b/samples/resources/Sample_42_TemplateSetCheckbox.docx
new file mode 100644
index 0000000000..9abc486b69
Binary files /dev/null and b/samples/resources/Sample_42_TemplateSetCheckbox.docx differ
diff --git a/samples/resources/Sample_44_ExtractVariablesFromReaderWord2007.docx b/samples/resources/Sample_44_ExtractVariablesFromReaderWord2007.docx
new file mode 100644
index 0000000000..a9385e126c
Binary files /dev/null and b/samples/resources/Sample_44_ExtractVariablesFromReaderWord2007.docx differ
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/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 @@
+items;
}
/**
- * Get item by index
+ * 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];
@@ -59,10 +61,9 @@ public function getItem($index)
/**
* Set item.
*
- * @param int $index
- * @param \PhpOffice\PhpWord\Element\AbstractContainer $item
+ * @param ?T $item
*/
- public function setItem($index, $item)
+ public function setItem(int $index, $item): void
{
if (array_key_exists($index, $this->items)) {
$this->items[$index] = $item;
@@ -70,25 +71,22 @@ public function setItem($index, $item)
}
/**
- * Add new item
+ * 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() + 1;
+ $index = $this->countItems();
$this->items[$index] = $item;
return $index;
}
/**
- * Get item count
- *
- * @return int
+ * Get item count.
*/
- 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 b5ffd5f40a..0694bf7dd8 100644
--- a/src/PhpWord/Collection/Bookmarks.php
+++ b/src/PhpWord/Collection/Bookmarks.php
@@ -1,4 +1,5 @@
*/
class Bookmarks extends AbstractCollection
{
diff --git a/src/PhpWord/Collection/Charts.php b/src/PhpWord/Collection/Charts.php
index aa807d1e58..ef1c6597ff 100644
--- a/src/PhpWord/Collection/Charts.php
+++ b/src/PhpWord/Collection/Charts.php
@@ -1,4 +1,5 @@
*/
class Charts extends AbstractCollection
{
diff --git a/src/PhpWord/Collection/Comments.php b/src/PhpWord/Collection/Comments.php
index b6c02d392f..4f1394359f 100644
--- a/src/PhpWord/Collection/Comments.php
+++ b/src/PhpWord/Collection/Comments.php
@@ -1,4 +1,5 @@
*/
class Comments extends AbstractCollection
{
diff --git a/src/PhpWord/Collection/Endnotes.php b/src/PhpWord/Collection/Endnotes.php
index db01b408db..3de1ad22d5 100644
--- a/src/PhpWord/Collection/Endnotes.php
+++ b/src/PhpWord/Collection/Endnotes.php
@@ -1,4 +1,5 @@
*/
class Endnotes extends AbstractCollection
{
diff --git a/src/PhpWord/Collection/Footnotes.php b/src/PhpWord/Collection/Footnotes.php
index a0a31ca494..804a45c873 100644
--- a/src/PhpWord/Collection/Footnotes.php
+++ b/src/PhpWord/Collection/Footnotes.php
@@ -1,4 +1,5 @@
*/
class Footnotes extends AbstractCollection
{
diff --git a/src/PhpWord/Collection/Titles.php b/src/PhpWord/Collection/Titles.php
index 1ea58ec0d6..1a943697d2 100644
--- a/src/PhpWord/Collection/Titles.php
+++ b/src/PhpWord/Collection/Titles.php
@@ -1,4 +1,5 @@
*/
class Titles extends AbstractCollection
{
diff --git a/src/PhpWord/ComplexType/FootnoteProperties.php b/src/PhpWord/ComplexType/FootnoteProperties.php
index e42c9f9d40..10c426e84c 100644
--- a/src/PhpWord/ComplexType/FootnoteProperties.php
+++ b/src/PhpWord/ComplexType/FootnoteProperties.php
@@ -1,4 +1,5 @@
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 +111,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 +126,7 @@ public function setNumFmt($numFmt)
}
/**
- * Get the Footnote Numbering Format
+ * Get the Footnote Numbering Format.
*
* @return float
*/
@@ -133,9 +136,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 +150,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 +160,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..0731238201 100644
--- a/src/PhpWord/ComplexType/ProofState.php
+++ b/src/PhpWord/ComplexType/ProofState.php
@@ -1,4 +1,5 @@
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 +80,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 +91,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/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 @@
+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/ComplexType/TblWidth.php b/src/PhpWord/ComplexType/TblWidth.php
index 0d1a2419a7..f1c0e10c9c 100644
--- a/src/PhpWord/ComplexType/TblWidth.php
+++ b/src/PhpWord/ComplexType/TblWidth.php
@@ -1,4 +1,5 @@
markup = $markup === null ? true : $markup;
}
/**
- * Get Display Comments
+ * Get Display Comments.
*
* @return bool True if comments are shown
*/
@@ -91,18 +92,18 @@ public function hasComments()
}
/**
- * Set Display Comments
+ * Set Display Comments.
*
- * @param bool $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 +113,18 @@ public function hasInsDel()
}
/**
- * Set Display Content Revisions
+ * Set Display Content Revisions.
*
- * @param bool $insDel
+ * @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 +134,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 +155,12 @@ public function hasInkAnnotations()
}
/**
- * Set Display Ink Annotations
+ * Set Display Ink Annotations.
*
- * @param bool $inkAnnotations
+ * @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 5e058667e5..37140b4582 100644
--- a/src/PhpWord/Element/AbstractContainer.php
+++ b/src/PhpWord/Element/AbstractContainer.php
@@ -1,4 +1,5 @@
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);
}
}
@@ -117,12 +126,13 @@ 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
+ *
+ * @return AbstractElement
*/
protected function addElement($elementName)
{
@@ -131,17 +141,17 @@ 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
- /** @var \PhpOffice\PhpWord\Element\AbstractElement $element Type hint */
+ /** @var AbstractElement $element Type hint */
$element = $reflection->newInstanceArgs($elementArgs);
// Set parent container
@@ -155,9 +165,9 @@ protected function addElement($elementName)
}
/**
- * Get all elements
+ * Get all elements.
*
- * @return \PhpOffice\PhpWord\Element\AbstractElement[]
+ * @return AbstractElement[]
*/
public function getElements()
{
@@ -165,10 +175,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|AbstractElement
*/
public function getElement($index)
{
@@ -180,15 +191,15 @@ public function getElement($index)
}
/**
- * Removes the element at requested index
+ * Removes the element at requested index.
*
- * @param int|\PhpOffice\PhpWord\Element\AbstractElement $toRemove
+ * @param AbstractElement|int $toRemove
*/
- public function removeElement($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]);
@@ -200,7 +211,7 @@ public function removeElement($toRemove)
}
/**
- * Count elements
+ * Count elements.
*
* @return int
*/
@@ -210,59 +221,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', 'Header'],
+ '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')),
- '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}.");
}
}
@@ -273,43 +283,11 @@ 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}.");
}
}
}
return true;
}
-
- /**
- * Create textrun element
- *
- * @deprecated 0.10.0
- *
- * @param mixed $paragraphStyle
- *
- * @return \PhpOffice\PhpWord\Element\TextRun
- *
- * @codeCoverageIgnore
- */
- public function createTextRun($paragraphStyle = null)
- {
- return $this->addTextRun($paragraphStyle);
- }
-
- /**
- * Create footnote element
- *
- * @deprecated 0.10.0
- *
- * @param mixed $paragraphStyle
- *
- * @return \PhpOffice\PhpWord\Element\Footnote
- *
- * @codeCoverageIgnore
- */
- public function createFootnote($paragraphStyle = null)
- {
- return $this->addFootnote($paragraphStyle);
- }
}
diff --git a/src/PhpWord/Element/AbstractElement.php b/src/PhpWord/Element/AbstractElement.php
index e3e54ed426..3a29b68673 100644
--- a/src/PhpWord/Element/AbstractElement.php
+++ b/src/PhpWord/Element/AbstractElement.php
@@ -1,4 +1,5 @@
phpWord;
}
/**
* Set PhpWord as reference.
- *
- * @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 +179,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 +196,7 @@ public function getDocPart()
}
/**
- * Get doc part Id
+ * Get doc part Id.
*
* @return int
*/
@@ -205,7 +206,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 +221,7 @@ private function getMediaPart()
}
/**
- * Get element index
+ * Get element index.
*
* @return int
*/
@@ -234,13 +235,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 +253,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((string) mt_rand()), 0, 6);
}
/**
- * Get relation Id
+ * Get relation Id.
*
* @return int
*/
@@ -272,13 +273,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,66 +289,109 @@ public function getNestedLevel()
}
/**
- * Get comment start
- *
- * @return Comment
+ * Get comments start.
*/
- public function getCommentRangeStart()
+ public function getCommentsRangeStart(): ?Comments
{
- return $this->commentRangeStart;
+ return $this->commentsRangeStart;
}
/**
- * Set comment start
- *
- * @param Comment $value
+ * Get comment start.
*/
- public function setCommentRangeStart(Comment $value)
+ public function getCommentRangeStart(): ?Comment
+ {
+ if ($this->commentsRangeStart != null) {
+ return $this->commentsRangeStart->getItem($this->commentsRangeStart->countItems());
+ }
+
+ return null;
+ }
+
+ /**
+ * Set comment start.
+ */
+ 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);
+ 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 comment end
- *
- * @return Comment
+ * Get comments end.
*/
- public function getCommentRangeEnd()
+ public function getCommentsRangeEnd(): ?Comments
{
- return $this->commentRangeEnd;
+ return $this->commentsRangeEnd;
}
/**
- * Set comment end
- *
- * @param Comment $value
+ * Get comment end.
*/
- public function setCommentRangeEnd(Comment $value)
+ public function getCommentRangeEnd(): ?Comment
+ {
+ if ($this->commentsRangeEnd != null) {
+ return $this->commentsRangeEnd->getItem($this->commentsRangeEnd->countItems());
+ }
+
+ return null;
+ }
+
+ /**
+ * Set comment end.
+ */
+ 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');
+ }
+ if ($this->commentsRangeEnd == null) {
+ $this->commentsRangeEnd = new Comments();
}
- $this->commentRangeEnd = $value;
- $this->commentRangeEnd->setEndElement($this);
+ // 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);
}
+ /**
+ * Get parent element.
+ *
+ * @return null|AbstractElement
+ */
public function getParent()
{
return $this->parent;
}
/**
- * 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;
@@ -355,7 +399,7 @@ public function setParentContainer(self $container)
// Set nested level
$this->nestedLevel = $container->getNestedLevel();
if ($this->parentContainer == 'Cell') {
- $this->nestedLevel++;
+ ++$this->nestedLevel;
}
// Set phpword
@@ -371,18 +415,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';
}
@@ -405,10 +449,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);
@@ -416,7 +460,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
*/
@@ -426,16 +470,17 @@ public function isInSection()
}
/**
- * Set new style value
+ * Set new style value.
*
* @param mixed $styleObject Style object
- * @param mixed $styleValue Style value
+ * @param null|array|string|Style $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 {
@@ -446,17 +491,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
*/
@@ -466,33 +509,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 16b020d741..151d5a48bf 100644
--- a/src/PhpWord/Element/Bookmark.php
+++ b/src/PhpWord/Element/Bookmark.php
@@ -1,4 +1,5 @@
name = CommonText::toUTF8($name);
+ $this->name = SharedText::toUTF8($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..2adcc1ab54 100644
--- a/src/PhpWord/Element/Cell.php
+++ b/src/PhpWord/Element/Cell.php
@@ -1,4 +1,5 @@
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,9 +119,9 @@ public function getSeries()
}
/**
- * Get chart style
+ * 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 f3e87176ef..b404a6027e 100644
--- a/src/PhpWord/Element/CheckBox.php
+++ b/src/PhpWord/Element/CheckBox.php
@@ -1,4 +1,5 @@
name = CommonText::toUTF8($name);
+ $this->name = SharedText::toUTF8($name);
return $this;
}
/**
- * Get name content
+ * Get name content.
*
* @return string
*/
diff --git a/src/PhpWord/Element/Comment.php b/src/PhpWord/Element/Comment.php
index 96ad15ef4e..a6a2e29d56 100644
--- a/src/PhpWord/Element/Comment.php
+++ b/src/PhpWord/Element/Comment.php
@@ -1,4 +1,5 @@
startElement = $value;
- if ($value->getCommentRangeStart() == null) {
- $value->setCommentRangeStart($this);
- }
+ $value->setCommentRangeStart($this);
}
/**
- * Get the element where this comment starts
+ * Get the element where this comment starts.
*
- * @return \PhpOffice\PhpWord\Element\AbstractElement
+ * @return AbstractElement
*/
public function getStartElement()
{
@@ -98,22 +98,18 @@ public function getStartElement()
}
/**
- * Sets the element where this comment ends
- *
- * @param \PhpOffice\PhpWord\Element\AbstractElement $value
+ * Sets the element where this comment ends.
*/
- public function setEndElement(AbstractElement $value)
+ public function setEndElement(AbstractElement $value): void
{
$this->endElement = $value;
- if ($value->getCommentRangeEnd() == null) {
- $value->setCommentRangeEnd($this);
- }
+ $value->setCommentRangeEnd($this);
}
/**
- * Get the element where this comment ends
+ * 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 b962719502..d2f42eafd0 100644
--- a/src/PhpWord/Element/Endnote.php
+++ b/src/PhpWord/Element/Endnote.php
@@ -1,4 +1,5 @@
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'],
+ ],
+ 'FILENAME' => [
+ 'properties' => [
+ 'format' => ['Upper', 'Lower', 'FirstCap', 'Caps'],
+ ],
+ 'options' => ['Path', 'PreserveFormat'],
+ ],
+ 'REF' => [
+ 'properties' => ['name' => ''],
+ 'options' => ['f', 'h', 'n', 'p', 'r', 't', 'w'],
+ ],
+ ];
/**
- * Field type
+ * Field type.
*
* @var string
*/
protected $type;
/**
- * Field text
+ * Field text.
*
- * @var TextRun|string
+ * @var null|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 \PhpOffice\PhpWord\Style\Font
+ * @var Font|string
*/
protected $fontStyle;
/**
- * Create a new Field Element
+ * Set Font style.
+ *
+ * @param array|Font|string $style
+ *
+ * @return Font|string
+ */
+ 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 Font|string
+ */
+ public function getFontStyle()
+ {
+ return $this->fontStyle;
+ }
+
+ /**
+ * Create a new Field Element.
*
* @param string $type
* @param array $properties
* @param array $options
- * @param TextRun|string|null $text
+ * @param null|string|TextRun $text
+ * @param array|Font|string $fontStyle
*/
- public function __construct($type = null, $properties = array(), $options = array(), $text = null)
+ public function __construct($type = null, $properties = [], $options = [], $text = null, $fontStyle = null)
{
$this->setType($type);
$this->setProperties($properties);
$this->setOptions($options);
$this->setText($text);
+ $this->setFontStyle($fontStyle);
}
/**
- * Set Field type
+ * Set Field type.
*
* @param string $type
*
- * @throws \InvalidArgumentException
* @return string
*/
public function setType($type = null)
@@ -149,7 +197,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'");
}
}
@@ -157,7 +205,7 @@ public function setType($type = null)
}
/**
- * Get Field type
+ * Get Field type.
*
* @return string
*/
@@ -167,29 +215,24 @@ public function getType()
}
/**
- * Set Field properties
+ * Set Field properties.
*
- * @param array $properties
- *
- * @throws \InvalidArgumentException
* @return self
*/
- public function setProperties($properties = array())
+ 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;
}
/**
- * Get Field properties
+ * Get Field properties.
*
* @return array
*/
@@ -199,29 +242,24 @@ public function getProperties()
}
/**
- * Set Field options
+ * Set Field options.
*
- * @param array $options
- *
- * @throws \InvalidArgumentException
* @return self
*/
- public function setOptions($options = array())
+ 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;
}
/**
- * Get Field properties
+ * Get Field properties.
*
* @return array
*/
@@ -231,20 +269,19 @@ public function getOptions()
}
/**
- * Set Field text
+ * Set Field text.
*
- * @param string|TextRun $text
+ * @param null|mixed|string|TextRun $text
*
- * @throws \InvalidArgumentException
* @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 {
- throw new \InvalidArgumentException('Invalid text');
+ throw new InvalidArgumentException('Invalid text');
}
}
@@ -252,7 +289,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..d17db10a32 100644
--- a/src/PhpWord/Element/Footer.php
+++ b/src/PhpWord/Element/Footer.php
@@ -1,4 +1,5 @@
type = $value;
}
/**
- * Get type
+ * Get type.
*
* @return string
+ *
* @since 0.10.0
*/
public function getType()
@@ -85,7 +88,7 @@ public function getType()
}
/**
- * Reset type to default
+ * Reset type to default.
*
* @return string
*/
@@ -95,7 +98,7 @@ public function resetType()
}
/**
- * First page only header
+ * First page only header.
*
* @return string
*/
@@ -105,7 +108,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..6f959c2432 100644
--- a/src/PhpWord/Element/Footnote.php
+++ b/src/PhpWord/Element/Footnote.php
@@ -1,4 +1,5 @@
paragraphStyle;
}
-
- /**
- * Get Footnote Reference ID
- *
- * @deprecated 0.10.0
- * @codeCoverageIgnore
- *
- * @return int
- */
- public function getReferenceId()
- {
- return $this->getRelationId();
- }
-
- /**
- * Set Footnote Reference ID
- *
- * @deprecated 0.10.0
- * @codeCoverageIgnore
- *
- * @param int $rId
- */
- public function setReferenceId($rId)
- {
- $this->setRelationId($rId);
- }
}
diff --git a/src/PhpWord/Element/FormField.php b/src/PhpWord/Element/FormField.php
index f937df59c4..5318134584 100644
--- a/src/PhpWord/Element/FormField.php
+++ b/src/PhpWord/Element/FormField.php
@@ -1,4 +1,5 @@
type = $this->setEnumVal($value, $enum, $this->type);
return $this;
}
/**
- * Get name
+ * Get name.
*
- * @return string
+ * @return ?string
*/
public function getName()
{
@@ -112,9 +114,10 @@ public function getName()
}
/**
- * Set name
+ * Set name.
+ *
+ * @param ?string $value
*
- * @param string|bool|int $value
* @return self
*/
public function setName($value)
@@ -125,9 +128,9 @@ public function setName($value)
}
/**
- * Get default
+ * Get default.
*
- * @return string|bool|int
+ * @return bool|int|string
*/
public function getDefault()
{
@@ -135,9 +138,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 +152,9 @@ public function setDefault($value)
}
/**
- * Get value
+ * Get value.
*
- * @return string|bool|int
+ * @return null|bool|int|string
*/
public function getValue()
{
@@ -158,9 +162,10 @@ public function getValue()
}
/**
- * Set value
+ * Set value.
+ *
+ * @param null|bool|int|string $value
*
- * @param string|bool|int $value
* @return self
*/
public function setValue($value)
@@ -171,7 +176,7 @@ public function setValue($value)
}
/**
- * Get entries
+ * Get entries.
*
* @return array
*/
@@ -181,9 +186,10 @@ public function getEntries()
}
/**
- * Set entries
+ * Set entries.
*
* @param array $value
+ *
* @return self
*/
public function setEntries($value)
diff --git a/tests/PhpWord/Element/PageBreakTest.php b/src/PhpWord/Element/Formula.php
similarity index 60%
rename from tests/PhpWord/Element/PageBreakTest.php
rename to src/PhpWord/Element/Formula.php
index d4491fe1b3..76bef4f683 100644
--- a/tests/PhpWord/Element/PageBreakTest.php
+++ b/src/PhpWord/Element/Formula.php
@@ -1,4 +1,5 @@
setMath($math);
+ }
+
+ public function setMath(Math $math): self
{
- $oPageBreak = new PageBreak();
+ $this->math = $math;
- $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\PageBreak', $oPageBreak);
+ return $this;
+ }
+
+ public function getMath(): Math
+ {
+ return $this->math;
}
}
diff --git a/src/PhpWord/Element/Header.php b/src/PhpWord/Element/Header.php
index 8a01946ea9..81a493f3f2 100644
--- a/src/PhpWord/Element/Header.php
+++ b/src/PhpWord/Element/Header.php
@@ -1,4 +1,5 @@
name = $value;
}
/**
- * Get image name
+ * Get image name.
*
* @return null|string
*/
@@ -200,7 +208,7 @@ public function getName()
}
/**
- * Get image media ID
+ * Get image media ID.
*
* @return string
*/
@@ -210,7 +218,7 @@ public function getMediaId()
}
/**
- * Get is watermark
+ * Get is watermark.
*
* @return bool
*/
@@ -220,17 +228,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 +248,7 @@ public function getImageType()
}
/**
- * Get image create function
+ * Get image create function.
*
* @return string
*/
@@ -250,17 +258,25 @@ public function getImageCreateFunction()
}
/**
- * Get image function
+ * Get image function.
*
- * @return string
+ * @return null|callable(resource): void
*/
- public function getImageFunction()
+ public function getImageFunction(): ?callable
{
return $this->imageFunc;
}
/**
- * Get image extension
+ * Get image quality.
+ */
+ public function getImageQuality(): ?int
+ {
+ return $this->imageQuality;
+ }
+
+ /**
+ * Get image extension.
*
* @return string
*/
@@ -270,7 +286,7 @@ public function getImageExtension()
}
/**
- * Get is memory image
+ * Get is memory image.
*
* @return bool
*/
@@ -280,7 +296,7 @@ public function isMemImage()
}
/**
- * Get target file name
+ * Get target file name.
*
* @return string
*/
@@ -294,13 +310,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,31 +330,26 @@ public function getMediaIndex()
*
* @param int $value
*/
- public function setMediaIndex($value)
+ public function setMediaIndex($value): void
{
$this->mediaIndex = $value;
}
/**
- * Get image string data
- *
- * @param bool $base64
- * @return string|null
- * @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
// 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) {
@@ -368,41 +379,56 @@ 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) {
$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);
}
}
- 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;
}
/**
- * Check memory image, supported type, image functions, and proportional width/height.
+ * Get image string data.
+ *
+ * @param bool $base64
*
- * @throws \PhpOffice\PhpWord\Exception\InvalidImageException
- * @throws \PhpOffice\PhpWord\Exception\UnsupportedImageTypeException
+ * @return null|string
+ *
+ * @since 0.11.0
+ */
+ public function getImageStringData($base64 = false)
+ {
+ $imageBinary = $this->getImageString();
+ if ($imageBinary === null) {
+ return null;
+ }
+
+ if ($base64) {
+ return base64_encode($imageBinary);
+ }
+
+ return bin2hex($imageBinary);
+ }
+
+ /**
+ * Check memory image, supported type, image functions, and proportional width/height.
*/
- private function checkImage()
+ private function checkImage(): void
{
$this->setSourceType();
@@ -410,19 +436,19 @@ 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);
}
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 +463,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;
@@ -454,7 +480,7 @@ private function setSourceType()
} else {
$this->sourceType = self::SOURCE_GD;
}
- } elseif (@file_exists($this->source)) {
+ } elseif ((strpos($this->source, chr(0)) === false) && @file_exists($this->source)) {
$this->memoryImage = false;
$this->sourceType = self::SOURCE_LOCAL;
} else {
@@ -464,21 +490,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) {
@@ -501,55 +525,54 @@ 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.
*/
- 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->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;
}
}
@@ -560,7 +583,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();
@@ -575,28 +598,4 @@ private function setProportionalSize($actualWidth, $actualHeight)
}
}
}
-
- /**
- * Get is watermark
- *
- * @deprecated 0.10.0
- *
- * @codeCoverageIgnore
- */
- public function getIsWatermark()
- {
- return $this->isWatermark();
- }
-
- /**
- * Get is memory image
- *
- * @deprecated 0.10.0
- *
- * @codeCoverageIgnore
- */
- public function getIsMemImage()
- {
- return $this->isMemImage();
- }
}
diff --git a/src/PhpWord/Element/Line.php b/src/PhpWord/Element/Line.php
index 7e40b9402d..b3ad438197 100644
--- a/src/PhpWord/Element/Line.php
+++ b/src/PhpWord/Element/Line.php
@@ -1,4 +1,5 @@
source = CommonText::toUTF8($source);
- $this->text = is_null($text) ? $this->source : CommonText::toUTF8($text);
+ $this->source = SharedText::toUTF8($source);
+ $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,19 +98,17 @@ public function getSource()
}
/**
- * Get link text
- *
- * @return string
+ * Get link text.
*/
- public function getText()
+ public function getText(): string
{
return $this->text;
}
/**
- * Get Text style
+ * Get Text style.
*
- * @return string|\PhpOffice\PhpWord\Style\Font
+ * @return null|Font|string
*/
public function getFontStyle()
{
@@ -117,9 +116,9 @@ public function getFontStyle()
}
/**
- * Get Paragraph style
+ * Get Paragraph style.
*
- * @return string|\PhpOffice\PhpWord\Style\Paragraph
+ * @return null|Paragraph|string
*/
public function getParagraphStyle()
{
@@ -127,49 +126,7 @@ public function getParagraphStyle()
}
/**
- * Get link target
- *
- * @deprecated 0.12.0
- *
- * @return string
- *
- * @codeCoverageIgnore
- */
- public function getTarget()
- {
- return $this->source;
- }
-
- /**
- * Get Link source
- *
- * @deprecated 0.10.0
- *
- * @return string
- *
- * @codeCoverageIgnore
- */
- public function getLinkSrc()
- {
- return $this->getSource();
- }
-
- /**
- * Get Link name
- *
- * @deprecated 0.10.0
- *
- * @return string
- *
- * @codeCoverageIgnore
- */
- public function getLinkName()
- {
- return $this->getText();
- }
-
- /**
- * is internal
+ * is internal.
*
* @return bool
*/
diff --git a/src/PhpWord/Element/ListItem.php b/src/PhpWord/Element/ListItem.php
index 8b064c47b5..bedfd110b6 100644
--- a/src/PhpWord/Element/ListItem.php
+++ b/src/PhpWord/Element/ListItem.php
@@ -1,4 +1,5 @@
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
- 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,9 +70,9 @@ public function __construct($text, $depth = 0, $fontStyle = null, $listStyle = n
}
/**
- * Get style
+ * Get style.
*
- * @return \PhpOffice\PhpWord\Style\ListItem
+ * @return ?ListItemStyle
*/
public function getStyle()
{
@@ -79,9 +80,9 @@ public function getStyle()
}
/**
- * Get Text object
+ * Get Text object.
*
- * @return \PhpOffice\PhpWord\Element\Text
+ * @return Text
*/
public function getTextObject()
{
@@ -89,7 +90,7 @@ public function getTextObject()
}
/**
- * Get depth
+ * Get depth.
*
* @return int
*/
@@ -99,9 +100,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..01d0947b81 100644
--- a/src/PhpWord/Element/ListItemRun.php
+++ b/src/PhpWord/Element/ListItemRun.php
@@ -1,26 +1,27 @@
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);
@@ -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 1a17b74753..8e447873a7 100644
--- a/src/PhpWord/Element/OLEObject.php
+++ b/src/PhpWord/Element/OLEObject.php
@@ -1,4 +1,5 @@
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;
}
@@ -90,7 +88,7 @@ public function __construct($source, $style = null)
}
/**
- * Get object source
+ * Get object source.
*
* @return string
*/
@@ -100,9 +98,9 @@ public function getSource()
}
/**
- * Get object style
+ * Get object style.
*
- * @return \PhpOffice\PhpWord\Style\Image
+ * @return ?ImageStyle
*/
public function getStyle()
{
@@ -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,36 +132,8 @@ public function getImageRelationId()
*
* @param int $rId
*/
- public function setImageRelationId($rId)
+ public function setImageRelationId($rId): void
{
$this->imageRelationId = $rId;
}
-
- /**
- * Get Object ID
- *
- * @deprecated 0.10.0
- *
- * @return int
- *
- * @codeCoverageIgnore
- */
- public function getObjectId()
- {
- return $this->relationId + 1325353440;
- }
-
- /**
- * Set Object ID
- *
- * @deprecated 0.10.0
- *
- * @param int $objId
- *
- * @codeCoverageIgnore
- */
- public function setObjectId($objId)
- {
- $this->relationId = $objId;
- }
}
diff --git a/src/PhpWord/Element/PageBreak.php b/src/PhpWord/Element/PageBreak.php
index 1e2ada80ad..950f0b7d5f 100644
--- a/src/PhpWord/Element/PageBreak.php
+++ b/src/PhpWord/Element/PageBreak.php
@@ -1,4 +1,5 @@
fontStyle = $this->setNewStyle(new Font('text'), $fontStyle);
$this->paragraphStyle = $this->setNewStyle(new Paragraph(), $paragraphStyle);
- $this->text = CommonText::toUTF8($text);
- $matches = preg_split('/({.*?})/', $this->text, null, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
+ $this->text = SharedText::toUTF8($text);
+ $matches = preg_split('/({.*?})/', $this->text ?? '', -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
if (isset($matches[0])) {
$this->text = $matches;
}
}
/**
- * Get Text style
+ * Get Text style.
*
- * @return string|\PhpOffice\PhpWord\Style\Font
+ * @return null|Font|string
*/
public function getFontStyle()
{
@@ -77,9 +78,9 @@ public function getFontStyle()
}
/**
- * Get Paragraph style
+ * Get Paragraph style.
*
- * @return string|\PhpOffice\PhpWord\Style\Paragraph
+ * @return null|Paragraph|string
*/
public function getParagraphStyle()
{
@@ -87,9 +88,9 @@ public function getParagraphStyle()
}
/**
- * Get Text content
+ * Get Text content.
*
- * @return string|array
+ * @return null|array|string
*/
public function getText()
{
diff --git a/src/PhpWord/Element/Row.php b/src/PhpWord/Element/Row.php
index da4dfe5d73..af8c19dd84 100644
--- a/src/PhpWord/Element/Row.php
+++ b/src/PhpWord/Element/Row.php
@@ -1,4 +1,5 @@
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/SDT.php b/src/PhpWord/Element/SDT.php
index 5548f768c7..62a66c0426 100644
--- a/src/PhpWord/Element/SDT.php
+++ b/src/PhpWord/Element/SDT.php
@@ -1,4 +1,5 @@
type = $this->setEnumVal($value, $enum, 'comboBox');
return $this;
}
/**
- * Get value
+ * Get value.
*
- * @return string|bool|int
+ * @return null|bool|int|string
*/
public function getValue()
{
@@ -107,9 +109,10 @@ public function getValue()
}
/**
- * Set value
+ * Set value.
+ *
+ * @param null|bool|int|string $value
*
- * @param string|bool|int $value
* @return self
*/
public function setValue($value)
@@ -120,7 +123,7 @@ public function setValue($value)
}
/**
- * Get listItems
+ * Get listItems.
*
* @return array
*/
@@ -130,9 +133,10 @@ public function getListItems()
}
/**
- * Set listItems
+ * Set listItems.
*
* @param array $value
+ *
* @return self
*/
public function setListItems($value)
@@ -143,7 +147,7 @@ public function setListItems($value)
}
/**
- * Get tag
+ * Get tag.
*
* @return string
*/
@@ -153,9 +157,10 @@ public function getTag()
}
/**
- * Set tag
+ * Set tag.
*
* @param string $tag
+ *
* @return self
*/
public function setTag($tag)
@@ -166,7 +171,7 @@ public function setTag($tag)
}
/**
- * Get alias
+ * Get alias.
*
* @return string
*/
@@ -176,9 +181,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 b495ef7bca..0ae00aa9f6 100644
--- a/src/PhpWord/Element/Section.php
+++ b/src/PhpWord/Element/Section.php
@@ -1,4 +1,5 @@
style->setStyleByArray($style);
}
}
/**
- * Get section style
+ * Get section style.
*
- * @return \PhpOffice\PhpWord\Style\Section
+ * @return ?SectionStyle
*/
public function getStyle()
{
@@ -94,7 +94,7 @@ public function getStyle()
}
/**
- * Add header
+ * Add header.
*
* @since 0.10.0
*
@@ -108,7 +108,7 @@ public function addHeader($type = Header::AUTO)
}
/**
- * Add footer
+ * Add footer.
*
* @since 0.10.0
*
@@ -122,7 +122,7 @@ public function addFooter($type = Header::AUTO)
}
/**
- * Get header elements
+ * Get header elements.
*
* @return Header[]
*/
@@ -132,7 +132,7 @@ public function getHeaders()
}
/**
- * Get footer elements
+ * Get footer elements.
*
* @return Footer[]
*/
@@ -142,21 +142,19 @@ public function getFooters()
}
/**
- * Get the footnote properties
+ * Get the footnote properties.
*
* @return FootnoteProperties
*/
- public function getFootnotePropoperties()
+ public function getFootnoteProperties()
{
return $this->footnoteProperties;
}
/**
- * Set the footnote properties
- *
- * @param FootnoteProperties $footnoteProperties
+ * Set the footnote properties.
*/
- public function setFootnoteProperties(FootnoteProperties $footnoteProperties = null)
+ public function setFootnoteProperties(?FootnoteProperties $footnoteProperties = null): void
{
$this->footnoteProperties = $footnoteProperties;
}
@@ -186,27 +184,25 @@ 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, '\\') ?: 0) . '\\' .
($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 */
+ /** @var AbstractContainer $container Type hint */
$container = new $containerClass($this->sectionId, ++$index, $type);
$container->setPhpWord($this->phpWord);
@@ -214,80 +210,7 @@ private function addHeaderFooter($type = Header::AUTO, $header = true)
return $container;
}
- throw new \Exception('Invalid header/footer type.');
- }
-
- /**
- * Set section style
- *
- * @deprecated 0.12.0
- *
- * @param array $settings
- *
- * @codeCoverageIgnore
- */
- public function setSettings($settings = null)
- {
- $this->setStyle($settings);
- }
-
- /**
- * Get section style
- *
- * @deprecated 0.12.0
- *
- * @return \PhpOffice\PhpWord\Style\Section
- *
- * @codeCoverageIgnore
- */
- public function getSettings()
- {
- return $this->getStyle();
- }
-
- /**
- * Create header
- *
- * @deprecated 0.10.0
- *
- * @return Header
- *
- * @codeCoverageIgnore
- */
- public function createHeader()
- {
- return $this->addHeader();
- }
-
- /**
- * Create footer
- *
- * @deprecated 0.10.0
- *
- * @return Footer
- *
- * @codeCoverageIgnore
- */
- public function createFooter()
- {
- return $this->addFooter();
- }
-
- /**
- * Get footer
- *
- * @deprecated 0.10.0
- *
- * @return Footer
- *
- * @codeCoverageIgnore
- */
- public function getFooter()
- {
- if (empty($this->footers)) {
- return null;
- }
- return $this->footers[1];
+ throw new Exception('Invalid header/footer type.');
}
}
diff --git a/src/PhpWord/Element/Shape.php b/src/PhpWord/Element/Shape.php
index d143c9b694..9ea221db3b 100644
--- a/src/PhpWord/Element/Shape.php
+++ b/src/PhpWord/Element/Shape.php
@@ -1,4 +1,5 @@
type = $this->setEnumVal($value, $enum, null);
return $this;
}
/**
- * Get shape style
+ * 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 c51d0e6be3..9e784c75df 100644
--- a/src/PhpWord/Element/TOC.php
+++ b/src/PhpWord/Element/TOC.php
@@ -1,4 +1,5 @@
TOCStyle = new TOCStyle();
+ $this->tocStyle = new TOCStyle();
- if (!is_null($tocStyle) && is_array($tocStyle)) {
- $this->TOCStyle->setStyleByArray($tocStyle);
+ if (null !== $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,19 +82,19 @@ 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();
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]);
@@ -108,19 +108,19 @@ public function getTitles()
}
/**
- * Get TOC Style
+ * Get TOC Style.
*
- * @return \PhpOffice\PhpWord\Style\TOC
+ * @return TOCStyle
*/
public function getStyleTOC()
{
- return $this->TOCStyle;
+ return $this->tocStyle;
}
/**
- * Get Font Style
+ * Get Font Style.
*
- * @return \PhpOffice\PhpWord\Style\Font|string
+ * @return Font|string
*/
public function getStyleFont()
{
@@ -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..7fb1030638 100644
--- a/src/PhpWord/Element/Table.php
+++ b/src/PhpWord/Element/Table.php
@@ -1,4 +1,5 @@
width = $width;
}
/**
- * Get column count
+ * Get column count.
*
* @return int
*/
@@ -137,8 +140,8 @@ public function countColumns()
$columnCount = 0;
$rowCount = count($this->rows);
- for ($i = 0; $i < $rowCount; $i++) {
- /** @var \PhpOffice\PhpWord\Element\Row $row Type hint */
+ for ($i = 0; $i < $rowCount; ++$i) {
+ /** @var Row $row Type hint */
$row = $this->rows[$i];
$cellCount = count($row->getCells());
if ($columnCount < $cellCount) {
@@ -150,20 +153,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 f4d7f08185..f20b273e02 100644
--- a/src/PhpWord/Element/Text.php
+++ b/src/PhpWord/Element/Text.php
@@ -1,4 +1,5 @@
text = CommonText::toUTF8($text);
+ $this->text = SharedText::toUTF8($text);
return $this;
}
/**
- * Get Text content
- *
- * @return string
+ * Get Text content.
*/
- public function getText()
+ public function getText(): ?string
{
return $this->text;
}
diff --git a/src/PhpWord/Element/TextBox.php b/src/PhpWord/Element/TextBox.php
index b9f274d6b8..b9f8b50bc5 100644
--- a/src/PhpWord/Element/TextBox.php
+++ b/src/PhpWord/Element/TextBox.php
@@ -1,4 +1,5 @@
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 Font|string
*/
public function setFontStyle($style = null, $paragraphStyle = null)
{
@@ -79,9 +81,9 @@ public function setFontStyle($style = null, $paragraphStyle = null)
}
/**
- * Get Text style
+ * Get Text style.
*
- * @return string|\PhpOffice\PhpWord\Style\Font
+ * @return null|Font|string
*/
public function getFontStyle()
{
@@ -89,10 +91,11 @@ public function getFontStyle()
}
/**
- * Set Paragraph style
+ * Set Paragraph style.
+ *
+ * @param array|Paragraph|string $style
*
- * @param string|array|\PhpOffice\PhpWord\Style\Paragraph $style
- * @return string|\PhpOffice\PhpWord\Style\Paragraph
+ * @return Paragraph|string
*/
public function setParagraphStyle($style = null)
{
@@ -109,9 +112,9 @@ public function setParagraphStyle($style = null)
}
/**
- * Get Paragraph style
+ * Get Paragraph style.
*
- * @return string|\PhpOffice\PhpWord\Style\Paragraph
+ * @return null|Paragraph|string
*/
public function getParagraphStyle()
{
@@ -119,12 +122,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..0c9a2322a7 100644
--- a/src/PhpWord/Element/TextRun.php
+++ b/src/PhpWord/Element/TextRun.php
@@ -1,4 +1,5 @@
paragraphStyle;
}
+
+ public function getText(): string
+ {
+ $outstr = '';
+ foreach ($this->getElements() as $element) {
+ if ($element instanceof Text) {
+ $outstr .= $element->getText();
+ } elseif ($element instanceof Ruby) {
+ $outstr .= $element->getBaseTextRun()->getText() .
+ ' (' . $element->getRubyTextRun()->getText() . ')';
+ }
+ }
+
+ return $outstr;
+ }
}
diff --git a/src/PhpWord/Element/Title.php b/src/PhpWord/Element/Title.php
index d01f7f339d..89f438a5ef 100644
--- a/src/PhpWord/Element/Title.php
+++ b/src/PhpWord/Element/Title.php
@@ -1,4 +1,5 @@
text = CommonText::toUTF8($text);
+ $this->text = SharedText::toUTF8($text);
} 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;
@@ -74,12 +83,16 @@ public function __construct($text, $depth = 1)
if (array_key_exists($styleName, Style::getStyles())) {
$this->style = str_replace('_', '', $styleName);
}
+
+ if ($pageNumber !== null) {
+ $this->pageNumber = $pageNumber;
+ }
}
/**
- * Get Title Text content
+ * Get Title Text content.
*
- * @return string
+ * @return string|TextRun
*/
public function getText()
{
@@ -87,7 +100,7 @@ public function getText()
}
/**
- * Get depth
+ * Get depth.
*
* @return int
*/
@@ -97,12 +110,20 @@ public function getDepth()
}
/**
- * Get Title style
+ * Get Title style.
*
- * @return string
+ * @return ?string
*/
public function getStyle()
{
return $this->style;
}
+
+ /**
+ * Get page number.
+ */
+ public function getPageNumber(): ?int
+ {
+ return $this->pageNumber;
+ }
}
diff --git a/src/PhpWord/Element/TrackChange.php b/src/PhpWord/Element/TrackChange.php
index 91c221f2a8..3539bdc627 100644
--- a/src/PhpWord/Element/TrackChange.php
+++ b/src/PhpWord/Element/TrackChange.php
@@ -1,4 +1,5 @@
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 +84,9 @@ public function getAuthor()
}
/**
- * Get TrackChange Date
+ * Get TrackChange Date.
*
- * @return \DateTime
+ * @return DateTime
*/
public function getDate()
{
@@ -90,7 +94,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..9c5dca39e0 100644
--- a/src/PhpWord/Escaper/AbstractEscaper.php
+++ b/src/PhpWord/Escaper/AbstractEscaper.php
@@ -1,4 +1,5 @@
$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,19 +42,20 @@ protected function escapeAsciiCharacter($code)
protected function escapeMultibyteCharacter($code)
{
- return '\uc0{\u' . $code . '}';
+ return '\\uc0{\\u' . $code . '}';
}
/**
* @see http://www.randomchaos.com/documents/?source=php_and_unicode
- * @param string $input
+ *
+ * @param ?string $input
*/
protected function escapeSingleValue($input)
{
$escapedValue = '';
$numberOfBytes = 1;
- $bytes = array();
+ $bytes = [];
for ($i = 0; $i < strlen($input); ++$i) {
$character = $input[$i];
$asciiCode = ord($character);
@@ -81,7 +89,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 a769c5e189..70e9cc21a4 100644
--- a/src/PhpWord/Escaper/Xml.php
+++ b/src/PhpWord/Escaper/Xml.php
@@ -1,4 +1,5 @@
load($filename);
}
/**
- * Check if it's a concrete class (not abstract nor interface)
+ * 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 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).
*
* @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..0a340a0a3c 100644
--- a/src/PhpWord/Media.php
+++ b/src/PhpWord/Media.php
@@ -1,4 +1,5 @@
$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();
@@ -76,20 +74,22 @@ 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);
$image->setMediaIndex($mediaTypeCount);
+
break;
- // Objects
+ // Objects
case 'object':
$target = "{$container}_oleObject{$mediaTypeCount}.bin";
+
break;
- // Links
+ // Links
case 'link':
$target = $source;
+
break;
}
@@ -103,7 +103,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 +112,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 +127,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 +141,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 +173,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,172 +200,10 @@ private static function getElementsByType($container, $type = null)
}
/**
- * Reset media elements
- */
- public static function resetElements()
- {
- self::$elements = array();
- }
-
- /**
- * Add new Section Media Element
- *
- * @deprecated 0.10.0
- *
- * @param string $src
- * @param string $type
- * @param \PhpOffice\PhpWord\Element\Image $image
- *
- * @return int
- *
- * @codeCoverageIgnore
- */
- public static function addSectionMediaElement($src, $type, Image $image = null)
- {
- return self::addElement('section', $type, $src, $image);
- }
-
- /**
- * Add new Section Link Element
- *
- * @deprecated 0.10.0
- *
- * @param string $linkSrc
- *
- * @return int
- *
- * @codeCoverageIgnore
- */
- public static function addSectionLinkElement($linkSrc)
- {
- return self::addElement('section', 'link', $linkSrc);
- }
-
- /**
- * Get Section Media Elements
- *
- * @deprecated 0.10.0
- *
- * @param string $key
- *
- * @return array
- *
- * @codeCoverageIgnore
- */
- public static function getSectionMediaElements($key = null)
- {
- return self::getElements('section', $key);
- }
-
- /**
- * Get Section Media Elements Count
- *
- * @deprecated 0.10.0
- *
- * @param string $key
- *
- * @return int
- *
- * @codeCoverageIgnore
- */
- public static function countSectionMediaElements($key = null)
- {
- return self::countElements('section', $key);
- }
-
- /**
- * Add new Header Media Element
- *
- * @deprecated 0.10.0
- *
- * @param int $headerCount
- * @param string $src
- * @param \PhpOffice\PhpWord\Element\Image $image
- *
- * @return int
- *
- * @codeCoverageIgnore
- */
- public static function addHeaderMediaElement($headerCount, $src, Image $image = null)
- {
- return self::addElement("header{$headerCount}", 'image', $src, $image);
- }
-
- /**
- * Get Header Media Elements Count
- *
- * @deprecated 0.10.0
- *
- * @param string $key
- *
- * @return int
- *
- * @codeCoverageIgnore
- */
- public static function countHeaderMediaElements($key)
- {
- return self::countElements($key);
- }
-
- /**
- * Get Header Media Elements
- *
- * @deprecated 0.10.0
- *
- * @return array
- *
- * @codeCoverageIgnore
- */
- public static function getHeaderMediaElements()
- {
- return self::getElements('header');
- }
-
- /**
- * Add new Footer Media Element
- *
- * @deprecated 0.10.0
- *
- * @param int $footerCount
- * @param string $src
- * @param \PhpOffice\PhpWord\Element\Image $image
- *
- * @return int
- *
- * @codeCoverageIgnore
- */
- public static function addFooterMediaElement($footerCount, $src, Image $image = null)
- {
- return self::addElement("footer{$footerCount}", 'image', $src, $image);
- }
-
- /**
- * Get Footer Media Elements Count
- *
- * @deprecated 0.10.0
- *
- * @param string $key
- *
- * @return int
- *
- * @codeCoverageIgnore
- */
- public static function countFooterMediaElements($key)
- {
- return self::countElements($key);
- }
-
- /**
- * Get Footer Media Elements
- *
- * @deprecated 0.10.0
- *
- * @return array
- *
- * @codeCoverageIgnore
+ * Reset media elements.
*/
- public static function getFooterMediaElements()
+ public static function resetElements(): void
{
- return self::getElements('footer');
+ self::$elements = [];
}
}
diff --git a/src/PhpWord/Metadata/Compatibility.php b/src/PhpWord/Metadata/Compatibility.php
index bf0363aa1a..b958d309b9 100644
--- a/src/PhpWord/Metadata/Compatibility.php
+++ b/src/PhpWord/Metadata/Compatibility.php
@@ -1,4 +1,5 @@
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 +533,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 +558,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 +575,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 15aa3ff189..667b1438e8 100644
--- a/src/PhpWord/Metadata/Protection.php
+++ b/src/PhpWord/Metadata/Protection.php
@@ -1,4 +1,5 @@
salt = $salt;
diff --git a/src/PhpWord/Metadata/Settings.php b/src/PhpWord/Metadata/Settings.php
index b1552e0210..0e30ec76d6 100644
--- a/src/PhpWord/Metadata/Settings.php
+++ b/src/PhpWord/Metadata/Settings.php
@@ -1,4 +1,5 @@
documentProtection = $documentProtection;
}
@@ -191,13 +203,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 +219,17 @@ public function hasHideSpellingErrors()
}
/**
- * Hide spelling errors
+ * Hide spelling errors.
*
- * @param bool $hideSpellingErrors
+ * @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 +239,11 @@ public function hasHideGrammaticalErrors()
}
/**
- * Hide grammatical errors
+ * Hide grammatical errors.
*
- * @param bool $hideGrammaticalErrors
+ * @param ?bool $hideGrammaticalErrors
*/
- public function setHideGrammaticalErrors($hideGrammaticalErrors)
+ public function setHideGrammaticalErrors($hideGrammaticalErrors): void
{
$this->hideGrammaticalErrors = $hideGrammaticalErrors === null ? true : $hideGrammaticalErrors;
}
@@ -245,17 +257,17 @@ public function hasEvenAndOddHeaders()
}
/**
- * @param bool $evenAndOddHeaders
+ * @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
+ * @return TrackChangesView
*/
public function getRevisionView()
{
@@ -263,11 +275,9 @@ public function getRevisionView()
}
/**
- * Set the Visibility of Annotation Types
- *
- * @param TrackChangesView $trackChangesView
+ * Set the Visibility of Annotation Types.
*/
- public function setRevisionView(TrackChangesView $trackChangesView = null)
+ public function setRevisionView(?TrackChangesView $trackChangesView = null): void
{
$this->revisionView = $trackChangesView;
}
@@ -281,9 +291,9 @@ public function hasTrackRevisions()
}
/**
- * @param bool $trackRevisions
+ * @param ?bool $trackRevisions
*/
- public function setTrackRevisions($trackRevisions)
+ public function setTrackRevisions($trackRevisions): void
{
$this->trackRevisions = $trackRevisions === null ? true : $trackRevisions;
}
@@ -297,9 +307,9 @@ public function hasDoNotTrackMoves()
}
/**
- * @param bool $doNotTrackMoves
+ * @param ?bool $doNotTrackMoves
*/
- public function setDoNotTrackMoves($doNotTrackMoves)
+ public function setDoNotTrackMoves($doNotTrackMoves): void
{
$this->doNotTrackMoves = $doNotTrackMoves === null ? true : $doNotTrackMoves;
}
@@ -313,9 +323,9 @@ public function hasDoNotTrackFormatting()
}
/**
- * @param bool $doNotTrackFormatting
+ * @param ?bool $doNotTrackFormatting
*/
- public function setDoNotTrackFormatting($doNotTrackFormatting)
+ public function setDoNotTrackFormatting($doNotTrackFormatting): void
{
$this->doNotTrackFormatting = $doNotTrackFormatting === null ? true : $doNotTrackFormatting;
}
@@ -331,7 +341,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,29 +363,27 @@ public function hasMirrorMargins()
/**
* @param bool $mirrorMargins
*/
- public function setMirrorMargins($mirrorMargins)
+ public function setMirrorMargins($mirrorMargins): void
{
$this->mirrorMargins = $mirrorMargins;
}
/**
- * Returns the Language
- *
- * @return Language
+ * Returns the 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)
+ public function setThemeFontLang(Language $themeFontLang): self
{
$this->themeFontLang = $themeFontLang;
+
+ return $this;
}
/**
@@ -387,15 +395,15 @@ public function hasUpdateFields()
}
/**
- * @param bool $updateFields
+ * @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 +413,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 +433,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 +449,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|int
*/
public function getHyphenationZone()
{
@@ -455,9 +463,9 @@ public function getHyphenationZone()
}
/**
- * @param float $hyphenationZone Measurement unit is twip
+ * @param null|float|int $hyphenationZone Measurement unit is twip
*/
- public function setHyphenationZone($hyphenationZone)
+ public function setHyphenationZone($hyphenationZone): void
{
$this->hyphenationZone = $hyphenationZone;
}
@@ -473,8 +481,20 @@ public function hasDoNotHyphenateCaps()
/**
* @param bool $doNotHyphenateCaps
*/
- public function setDoNotHyphenateCaps($doNotHyphenateCaps)
+ public function setDoNotHyphenateCaps($doNotHyphenateCaps): void
{
$this->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/PhpWord.php b/src/PhpWord/PhpWord.php
index a78df2c4e5..c3200fe857 100644
--- a/src/PhpWord/PhpWord.php
+++ b/src/PhpWord/PhpWord.php
@@ -1,4 +1,5 @@
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 +96,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");
}
@@ -155,25 +135,24 @@ 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(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
+ * @return Metadata\DocInfo
*/
public function getDocInfo()
{
@@ -181,22 +160,10 @@ public function getDocInfo()
}
/**
- * Get protection
+ * Get compatibility.
*
- * @return \PhpOffice\PhpWord\Metadata\Protection
- * @since 0.12.0
- * @deprecated Get the Document protection from PhpWord->getSettings()->getDocumentProtection();
- * @codeCoverageIgnore
- */
- public function getProtection()
- {
- return $this->getSettings()->getDocumentProtection();
- }
-
- /**
- * Get compatibility
+ * @return Metadata\Compatibility
*
- * @return \PhpOffice\PhpWord\Metadata\Compatibility
* @since 0.12.0
*/
public function getCompatibility()
@@ -205,9 +172,10 @@ public function getCompatibility()
}
/**
- * Get compatibility
+ * Get compatibility.
+ *
+ * @return Metadata\Settings
*
- * @return \PhpOffice\PhpWord\Metadata\Settings
* @since 0.14.0
*/
public function getSettings()
@@ -216,9 +184,9 @@ public function getSettings()
}
/**
- * Get all sections
+ * Get all sections.
*
- * @return \PhpOffice\PhpWord\Element\Section[]
+ * @return Section[]
*/
public function getSections()
{
@@ -226,10 +194,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|Section
*/
public function getSection($index)
{
@@ -241,10 +210,11 @@ public function getSection($index)
}
/**
- * Create new section
+ * Create new section.
*
- * @param array $style
- * @return \PhpOffice\PhpWord\Element\Section
+ * @param null|array|string $style
+ *
+ * @return Section
*/
public function addSection($style = null)
{
@@ -256,18 +226,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 +252,47 @@ public function getDefaultFontName()
*
* @param string $fontName
*/
- public function setDefaultFontName($fontName)
+ public function setDefaultFontName($fontName): void
{
Settings::setDefaultFontName($fontName);
}
/**
- * Get default font size
+ * Get default asian font name.
+ */
+ public function getDefaultAsianFontName(): string
+ {
+ return Settings::getDefaultAsianFontName();
+ }
+
+ /**
+ * Set default asian font name.
+ *
+ * @param string $fontName
+ */
+ 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.
*
* @return int
*/
@@ -301,16 +306,17 @@ 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
+ *
+ * @return Style\Paragraph
*/
public function setDefaultParagraphStyle($styles)
{
@@ -318,45 +324,25 @@ public function setDefaultParagraphStyle($styles)
}
/**
- * 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
- */
- 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,13 +362,13 @@ public function save($filename, $format = 'Word2007', $download = false)
}
/**
- * Create new section
+ * Create new section.
*
* @deprecated 0.10.0
*
* @param array $settings
*
- * @return \PhpOffice\PhpWord\Element\Section
+ * @return Section
*
* @codeCoverageIgnore
*/
@@ -392,11 +378,11 @@ public function createSection($settings = null)
}
/**
- * Get document properties object
+ * Get document properties object.
*
* @deprecated 0.12.0
*
- * @return \PhpOffice\PhpWord\Metadata\DocInfo
+ * @return Metadata\DocInfo
*
* @codeCoverageIgnore
*/
@@ -406,11 +392,11 @@ public function getDocumentProperties()
}
/**
- * Set document properties object
+ * Set document properties object.
*
* @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 7db285f758..3c70834d16 100644
--- a/src/PhpWord/Reader/AbstractReader.php
+++ b/src/PhpWord/Reader/AbstractReader.php
@@ -1,4 +1,5 @@
imageLoading;
+ }
+
+ public function setImageLoading(bool $value): self
+ {
+ $this->imageLoading = $value;
+
+ return $this;
+ }
+
/**
- * Open file for reading
+ * Open file for reading.
*
* @param string $filename
*
- * @throws \PhpOffice\PhpWord\Exception\Exception
- *
* @return resource
*/
protected function openFile($filename)
@@ -83,7 +102,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 +112,7 @@ protected function openFile($filename)
* Can the current ReaderInterface read the file?
*
* @param string $filename
+ *
* @return bool
*/
public function canRead($filename)
@@ -109,16 +129,4 @@ public function canRead($filename)
return true;
}
-
- /**
- * Read data only?
- *
- * @deprecated 0.10.0
- *
- * @codeCoverageIgnore
- */
- public function getReadDataOnly()
- {
- return $this->isReadDataOnly();
- }
}
diff --git a/src/PhpWord/Reader/HTML.php b/src/PhpWord/Reader/HTML.php
index db9f20891c..17871c21a2 100644
--- a/src/PhpWord/Reader/HTML.php
+++ b/src/PhpWord/Reader/HTML.php
@@ -1,4 +1,5 @@
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 1a9e4988bf..7cbeb1a8ac 100644
--- a/src/PhpWord/Reader/MsDoc.php
+++ b/src/PhpWord/Reader/MsDoc.php
@@ -1,4 +1,5 @@
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)
@@ -159,8 +169,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 +181,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 +219,7 @@ private function readFib($data)
// lKey
$pos += 4;
// envr
- $pos += 1;
+ ++$pos;
// $mem = self::getInt1d($data, $pos);
// $fMac = ($mem >> 7) & 1;
@@ -217,7 +228,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 +328,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 +354,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 +1116,7 @@ private function readBlockFibRgFcLcb($data, $pos, $version)
return $pos;
}
- private function readFibContent()
+ private function readFibContent(): void
{
// Informations about Font
$this->readRecordSttbfFfn();
@@ -1120,25 +1136,26 @@ private function readFibContent()
}
/**
- * Section and information about them
- * @see : http://msdn.microsoft.com/en-us/library/dd924458%28v=office.12%29.aspx
+ * 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);
$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 = 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 +1182,11 @@ private function readRecordPlcfSed()
}
/**
- * Specifies the fonts that are used in the document
- * @see : http://msdn.microsoft.com/en-us/library/dd943880%28v=office.12%29.aspx
+ * 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 +1196,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 +1233,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 +1261,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,10 +1280,12 @@ private function readRecordPlcfBtePapx()
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;
}
}
}
@@ -1436,15 +1457,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;
}
@@ -1455,34 +1477,34 @@ private function readRecordPlcfBteChpx()
$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 = 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;
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);
- $posRGB += 1;
+ ++$posRGB;
$oStyle->style = $this->readPrl($this->dataWorkDocument, $posRGB, $cb);
$posRGB += $oStyle->style->length;
@@ -1492,16 +1514,15 @@ 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 = ($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;
}
@@ -1509,7 +1530,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,64 +1546,75 @@ 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;
$sprmCFData = null;
- $sprmCFSpec = null;
+ //$sprmCFSpec = null;
do {
// Variables
@@ -1601,199 +1634,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);
+ $oStylePrl->styleFont['size'] = $operand / 2;
+
break;
- // sprmCIss
+ // sprmCIss
case 0x48:
if (!isset($oStylePrl->styleFont['superScript'])) {
$oStylePrl->styleFont['superScript'] = false;
@@ -1807,122 +1891,135 @@ 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;
+ //$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;
$cbNum -= 2;
+
// $ipat = ($operand >> 0) && bindec('111111');
// $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);
@@ -1954,7 +2052,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);
@@ -2022,8 +2120,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
@@ -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,14 +2189,14 @@ 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++) {
- $chr = self::getInt1d($this->dataData, $sprmCPicLocation);
- $sprmCPicLocation += 1;
- $stPicName .= chr($chr);
+ //$stPicName = '';
+ for ($inc = 0; $inc <= $cchPicName; ++$inc) {
+ //$chr = self::getInt1d($this->dataData, $sprmCPicLocation);
+ ++$sprmCPicLocation;
+ //$stPicName .= chr($chr);
}
}
@@ -2110,18 +2208,18 @@ 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 += 1;
+ ++$sprmCPicLocation;
// btMacOS
- $sprmCPicLocation += 1;
+ ++$sprmCPicLocation;
// rgbUid
$sprmCPicLocation += 16;
// tag
@@ -2133,31 +2231,31 @@ 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++) {
- $chr = self::getInt2d($this->dataData, $sprmCPicLocation);
+ //$nameData = '';
+ for ($inc = 0; $inc <= ($cbName / 2); ++$inc) {
+ //$chr = self::getInt2d($this->dataData, $sprmCPicLocation);
$sprmCPicLocation += 2;
- $nameData .= chr($chr);
+ //$nameData .= chr($chr);
}
}
// 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:
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();
@@ -2232,7 +2334,7 @@ private function generatePhpWord()
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) == '') {
@@ -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 0b58dc50e1..288bf9a0dd 100644
--- a/src/PhpWord/Reader/ODText.php
+++ b/src/PhpWord/Reader/ODText.php
@@ -1,4 +1,5 @@
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);
@@ -52,18 +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, array $relationships, string $partName, string $docFile, string $xmlFile): void
{
$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);
@@ -71,14 +67,11 @@ private function readPart(PhpWord $phpWord, $relationships, $partName, $docFile,
}
/**
- * Read all relationship files
- *
- * @param string $docFile
- * @return array
+ * Read all relationship files.
*/
- private function readRelationships($docFile)
+ private function readRelationships(string $docFile): array
{
- $rels = array();
+ $rels = [];
$xmlFile = 'META-INF/manifest.xml';
$xmlReader = new XMLReader();
$xmlReader->getDomFromZip($docFile, $xmlFile);
@@ -86,7 +79,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..447c96f094 100644
--- a/src/PhpWord/Reader/ODText/AbstractPart.php
+++ b/src/PhpWord/Reader/ODText/AbstractPart.php
@@ -1,4 +1,5 @@
getDomFromZip($this->docFile, $this->xmlFile);
- $trackedChanges = array();
-
$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
- $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;
- }
+ $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';
+
+ $xmlReaderObject = new XMLReader();
+ $mathElement = $xmlReaderObject->getDomFromZip($this->docFile, $mathFile);
+ if ($mathElement) {
+ $mathXML = $mathElement->saveXML($mathElement);
+
+ if (is_string($mathXML)) {
+ $reader = new MathML();
+ $math = $reader->read($mathXML);
+
+ $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':
+ $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;
+ case 'text:span':
+ $spans = true;
+
+ break;
+ }
+ }
+
+ 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;
+ }
+ }
- $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;
+ }
+ }
+ } 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 = $this->getSection($phpWord)->addText($changedNode->nodeValue);
+ $element->setTrackChange($changed['changed']);
+ }
}
}
}
+
break;
case 'text:list': // List
$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;
case 'text:tracked-changes':
$changedRegions = $xmlReader->getElements('text:changed-region', $node);
@@ -99,14 +174,33 @@ 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;
+ case 'text:section': // Section
+ // $sectionStyleName = $xmlReader->getAttribute('text:style-name', $listItem);
+ $this->section = $phpWord->addSection();
+ /** @var DOMNodeList $children */
+ $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/src/PhpWord/Reader/ODText/Meta.php b/src/PhpWord/Reader/ODText/Meta.php
index 8801a5439a..1321b6ce35 100644
--- a/src/PhpWord/Reader/ODText/Meta.php
+++ b/src/PhpWord/Reader/ODText/Meta.php
@@ -1,4 +1,5 @@
getDomFromZip($this->docFile, $this->xmlFile);
@@ -42,16 +42,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 +66,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..dbf1ebd7ad 100644
--- a/src/PhpWord/Reader/RTF.php
+++ b/src/PhpWord/Reader/RTF.php
@@ -1,4 +1,5 @@
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..59f0a7dd59 100644
--- a/src/PhpWord/Reader/RTF/Document.php
+++ b/src/PhpWord/Reader/RTF/Document.php
@@ -1,4 +1,5 @@
'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 +177,7 @@ public function read(PhpWord $phpWord)
}
}
}
- $this->offset++;
+ ++$this->offset;
}
$this->flushText();
}
@@ -184,7 +185,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 +194,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 +203,7 @@ private function markClosing()
/**
* Mark backslash `\` character.
*/
- private function markBackslash()
+ private function markBackslash(): void
{
if ($this->isFirst) {
$this->setControl(false);
@@ -217,7 +218,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 +230,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 +244,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 +259,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 +285,7 @@ private function flushText()
*
* @param bool $value
*/
- private function setControl($value)
+ private function setControl($value): void
{
$this->isControl = $value;
$this->isFirst = $value;
@@ -295,7 +296,7 @@ private function setControl($value)
*
* @param string $char
*/
- private function pushText($char)
+ private function pushText($char): void
{
if ('<' == $char) {
$this->text .= '<';
@@ -312,32 +313,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 +352,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 +364,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 +375,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 +385,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..1dced12aba 100644
--- a/src/PhpWord/Reader/ReaderInterface.php
+++ b/src/PhpWord/Reader/ReaderInterface.php
@@ -1,4 +1,5 @@
readRelationships($docFile);
-
- $steps = array(
- array('stepPart' => 'document', 'stepItems' => array(
- 'styles' => 'Styles',
- 'numbering' => 'Numbering',
- )),
- array('stepPart' => 'main', 'stepItems' => array(
- 'officeDocument' => 'Document',
- 'core-properties' => 'DocPropsCore',
- 'extended-properties' => 'DocPropsApp',
- 'custom-properties' => 'DocPropsCustom',
- )),
- array('stepPart' => 'document', 'stepItems' => array(
- 'endnotes' => 'Endnotes',
- 'footnotes' => 'Footnotes',
- 'settings' => 'Settings',
- )),
- );
+ $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',
+ ],
+ ],
+ ];
foreach ($steps as $step) {
$stepPart = $step['stepPart'];
@@ -70,7 +87,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();
}
}
}
@@ -81,32 +99,35 @@ public function load($docFile)
/**
* Read document part.
*
- * @param \PhpOffice\PhpWord\PhpWord $phpWord
- * @param array $relationships
- * @param string $partName
- * @param string $docFile
- * @param string $xmlFile
+ * @param array> $commentRefs
*/
- private function readPart(PhpWord $phpWord, $relationships, $partName, $docFile, $xmlFile)
+ 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->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;
}
/**
- * 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,10 +136,17 @@ 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 (!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/');
}
}
@@ -129,11 +157,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 +170,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 +192,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 bb4a3a4944..9d49573d69 100644
--- a/src/PhpWord/Reader/Word2007/AbstractPart.php
+++ b/src/PhpWord/Reader/Word2007/AbstractPart.php
@@ -1,4 +1,5 @@
>
+ */
+ protected $commentRefs = [];
+
+ /**
+ * Image Loading.
+ *
+ * @var bool
+ */
+ protected $imageLoading = true;
/**
* Read part.
@@ -71,7 +95,7 @@ abstract class AbstractPart
abstract public function read(PhpWord $phpWord);
/**
- * Create new instance
+ * Create new instance.
*
* @param string $docFile
* @param string $xmlFile
@@ -87,58 +111,177 @@ public function __construct($docFile, $xmlFile)
*
* @param array $value
*/
- public function setRels($value)
+ 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;
+ }
+
+ /**
+ * 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.
*
- * @param \PhpOffice\Common\XMLReader $xmlReader
- * @param \DOMElement $domNode
- * @param \PhpOffice\PhpWord\Element\AbstractContainer $parent
+ * @param 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;
- $headingDepth = null;
- 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)) {
+ 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);
$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();
}
- if (!is_null($instrText)) {
+ $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);
}
}
}
$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);
@@ -148,11 +291,17 @@ protected function readParagraph(XMLReader $xmlReader, \DOMElement $domNode, $pa
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', $domNode);
- if ($nodes->length === 1) {
+ $nodes = $xmlReader->getElements('w:r|w:hyperlink', $domNode);
+ $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);
@@ -161,35 +310,139 @@ protected function readParagraph(XMLReader $xmlReader, \DOMElement $domNode, $pa
}
}
$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(1, $paragraphStyle);
} else {
- // Text and TextRun
- $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);
- $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);
+ }
+ }
+ }
+
+ /**
+ * @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
+ * 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 +455,15 @@ private function getHeadingDepth(array $paragraphStyle = null)
/**
* Read w:r.
*
- * @param \PhpOffice\Common\XMLReader $xmlReader
- * @param \DOMElement $domNode
- * @param \PhpOffice\PhpWord\Element\AbstractContainer $parent
+ * @param 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', 'w:commentReference'])) {
$nodes = $xmlReader->getElements('*', $domNode);
foreach ($nodes as $node) {
$this->readRun($xmlReader, $node, $parent, $docPart, $paragraphStyle);
@@ -224,19 +475,27 @@ protected function readRun(XMLReader $xmlReader, \DOMElement $domNode, $parent,
$this->readRunChild($xmlReader, $node, $parent, $docPart, $paragraphStyle, $fontStyle);
}
}
+
+ 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));
+ }
+ }
}
/**
- * 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 +512,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 ($this->hasImageLoading() && null !== $target) {
if ('External' == $this->getTargetMode($docPart, $rId)) {
$imageSource = $target;
} else {
@@ -270,8 +529,12 @@ 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)) {
+ if ($this->hasImageLoading() && null !== $target) {
$imageSource = "zip://{$this->docFile}#{$target}";
$parent->addImage($imageSource, null, false, $name);
}
@@ -280,7 +543,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);
}
@@ -288,6 +551,19 @@ protected function readRunChild(XMLReader $xmlReader, \DOMElement $node, Abstrac
$parent->addTextBreak();
} elseif ($node->nodeName == 'w:tab') {
$parent->addText("\t");
+ } elseif ($node->nodeName == 'mc:AlternateContent') {
+ if ($node->hasChildNodes()) {
+ // Get fallback instead of mc:Choice to make sure it is compatible
+ $fallbackElements = $node->getElementsByTagName('Fallback');
+
+ if ($fallbackElements->length) {
+ $fallback = $fallbackElements->item(0);
+ // TextRun
+ $textContent = htmlspecialchars($fallback->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');
@@ -295,7 +571,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);
@@ -303,25 +579,64 @@ 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'));
+ $date = $date instanceof DateTime ? $date : null;
$element->setChangeInfo($type, $author, $date);
}
}
+ } 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.
*
- * @param \PhpOffice\Common\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;
@@ -339,11 +654,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);
@@ -353,9 +668,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 (!is_null($cellStyleNode)) {
- $cellStyle = $this->readCellStyle($xmlReader, $cellStyleNode);
+ if ($xmlReader->elementExists('w:tcPr', $rowNode)) {
+ $cellStyle = $this->readCellStyle($xmlReader, $rowNode);
}
$cell = $row->addCell($cellWidth, $cellStyle);
@@ -363,6 +677,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);
}
}
}
@@ -374,48 +690,59 @@ protected function readTable(XMLReader $xmlReader, \DOMElement $domNode, $parent
/**
* Read w:pPr.
*
- * @param \PhpOffice\Common\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'],
+ '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'],
+ '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'],
+ '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'],
+ '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);
}
/**
- * Read w:rPr
+ * Read w:rPr.
*
- * @param \PhpOffice\Common\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
@@ -427,64 +754,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\Common\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);
@@ -503,77 +829,87 @@ protected function readTableStyle(XMLReader $xmlReader, \DOMElement $domNode)
}
/**
- * Read w:tblpPr
+ * Read w:tblpPr.
*
- * @param \PhpOffice\Common\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\Common\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\Common\XMLReader $xmlReader
- * @param \DOMElement $domNode
- * @return array
+ * @return null|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', null, null, 'continue'],
+ '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;
}
/**
- * Returns the first child element found
+ * Returns the first child element found.
+ *
+ * @param null|array|string $elements
*
- * @param XMLReader $xmlReader
- * @param \DOMElement $parentNode
- * @param string|array $elements
- * @return string|null
+ * @return null|string
*/
- 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
@@ -590,14 +926,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)) {
@@ -614,20 +949,20 @@ private function findPossibleAttribute(XMLReader $xmlReader, \DOMElement $node,
}
/**
- * Read style definition
+ * Read style definition.
*
- * @param \PhpOffice\Common\XMLReader $xmlReader
- * @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, $default] = array_pad($styleVal, 5, null);
$element = $this->findPossibleElement($xmlReader, $parentNode, $element);
if ($element === null) {
@@ -641,7 +976,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) {
@@ -654,12 +989,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)
@@ -680,10 +1018,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)
@@ -692,17 +1032,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'];
}
@@ -710,17 +1051,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/Comments.php b/src/PhpWord/Reader/Word2007/Comments.php
new file mode 100644
index 0000000000..61b31713b5
--- /dev/null
+++ b/src/PhpWord/Reader/Word2007/Comments.php
@@ -0,0 +1,56 @@
+getDomFromZip($this->docFile, $this->xmlFile);
+
+ $comments = $phpWord->getComments();
+
+ $nodes = $xmlReader->getElements('*');
+
+ foreach ($nodes as $node) {
+ $name = str_replace('w:', '', $node->nodeName);
+
+ $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);
+
+ $range = $this->getCommentReference($xmlReader->getAttribute('w:id', $node));
+ if ($range['start']) {
+ $range['start']->setCommentRangeStart($element);
+ }
+ if ($range['end']) {
+ $range['end']->setCommentRangeEnd($element);
+ }
+
+ $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/DocPropsApp.php b/src/PhpWord/Reader/Word2007/DocPropsApp.php
index decc510390..c7ecb007b3 100644
--- a/src/PhpWord/Reader/Word2007/DocPropsApp.php
+++ b/src/PhpWord/Reader/Word2007/DocPropsApp.php
@@ -1,4 +1,5 @@
'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 36eecebeae..2458bb84cf 100644
--- a/src/PhpWord/Reader/Word2007/DocPropsCore.php
+++ b/src/PhpWord/Reader/Word2007/DocPropsCore.php
@@ -1,4 +1,5 @@
'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 a6835aacc1..442017199b 100644
--- a/src/PhpWord/Reader/Word2007/DocPropsCustom.php
+++ b/src/PhpWord/Reader/Word2007/DocPropsCustom.php
@@ -1,4 +1,5 @@
getDomFromZip($this->docFile, $this->xmlFile);
diff --git a/src/PhpWord/Reader/Word2007/Document.php b/src/PhpWord/Reader/Word2007/Document.php
index f0d1194a0b..89e479ef36 100644
--- a/src/PhpWord/Reader/Word2007/Document.php
+++ b/src/PhpWord/Reader/Word2007/Document.php
@@ -1,4 +1,5 @@
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 +65,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 +95,30 @@ private function readHeaderFooter($settings, Section &$section)
}
/**
- * Read w:sectPr
+ * Read w:sectPr.
*
- * @param \PhpOffice\Common\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 +127,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),
+ ];
}
}
@@ -140,14 +139,8 @@ private function readSectionStyle(XMLReader $xmlReader, \DOMElement $domNode)
/**
* Read w:p node.
- *
- * @param \PhpOffice\Common\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 +162,8 @@ private function readWPNode(XMLReader $xmlReader, \DOMElement $node, Section &$s
/**
* Read w:sectPr node.
- *
- * @param \PhpOffice\Common\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..6ab4203579 100644
--- a/src/PhpWord/Reader/Word2007/Endnotes.php
+++ b/src/PhpWord/Reader/Word2007/Endnotes.php
@@ -1,4 +1,5 @@
getDomFromZip($this->docFile, $this->xmlFile);
@@ -58,7 +57,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 +73,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 3f57cbf8be..564c43b23b 100644
--- a/src/PhpWord/Reader/Word2007/Numbering.php
+++ b/src/PhpWord/Reader/Word2007/Numbering.php
@@ -1,4 +1,5 @@
getDomFromZip($this->docFile, $this->xmlFile);
@@ -44,17 +44,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 +89,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\Common\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 +113,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 3084943b37..f4f8be6fb2 100644
--- a/src/PhpWord/Reader/Word2007/Settings.php
+++ b/src/PhpWord/Reader/Word2007/Settings.php
@@ -1,4 +1,5 @@
+ */
+ private $booleanProperties = [
'mirrorMargins',
'hideSpellingErrors',
'hideGrammaticalErrors',
@@ -40,14 +45,13 @@ class Settings extends AbstractPart
'updateFields',
'autoHyphenation',
'doNotHyphenateCaps',
- );
+ 'bookFoldPrinting',
+ ];
/**
* 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);
@@ -61,12 +65,8 @@ public function read(PhpWord $phpWord)
$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)) {
@@ -77,13 +77,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 +94,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 +107,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 +125,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 +138,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 +151,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 +160,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 97f29b4316..d0777c3026 100644
--- a/src/PhpWord/Reader/Word2007/Styles.php
+++ b/src/PhpWord/Reader/Word2007/Styles.php
@@ -1,4 +1,5 @@
getDomFromZip($this->docFile, $this->xmlFile);
@@ -41,14 +40,19 @@ public function read(PhpWord $phpWord)
$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('color', $fontDefaultStyle)) {
+ $phpWord->setDefaultFontColor($fontDefaultStyle['color']);
+ }
+ if (array_key_exists('lang', $fontDefaultStyle)) {
+ $phpWord->getSettings()->setThemeFontLang(new Language($fontDefaultStyle['lang']));
+ }
}
}
@@ -65,10 +69,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 +90,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 8de1a8df80..16f49166fa 100644
--- a/src/PhpWord/Settings.php
+++ b/src/PhpWord/Settings.php
@@ -1,124 +1,158 @@
0) {
+ if ((is_int($value) || is_float($value)) && (int) $value > 0) {
self::$defaultFontSize = $value;
return true;
@@ -389,58 +450,78 @@ public static function setDefaultFontSize($value)
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
- *
- * @param string $filename
- * @return array
+ * Load setting from phpword.yml or phpword.yml.dist.
*/
- public static function loadConfig($filename = null)
+ public static function loadConfig(?string $filename = null): array
{
// Get config file
$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 $config;
+ return [];
}
}
// Set config value
+ $appliedConfig = [];
foreach ($config as $key => $value) {
$method = "set{$key}";
if (method_exists(__CLASS__, $method)) {
self::$method($value);
+ $appliedConfig[$key] = $value;
}
}
- return $config;
+ return $appliedConfig;
}
/**
- * Return the compatibility option used by the XMLWriter
- *
- * @deprecated 0.10.0
- *
- * @codeCoverageIgnore
+ * Get default paper.
*/
- public static function getCompatibility()
+ public static function getDefaultPaper(): string
{
- return self::hasCompatibility();
+ return self::$defaultPaper;
+ }
+
+ /**
+ * Set default paper.
+ */
+ public static function setDefaultPaper(string $value): bool
+ {
+ if (trim($value) !== '') {
+ self::$defaultPaper = $value;
+
+ return true;
+ }
+
+ return false;
}
}
diff --git a/src/PhpWord/Shared/AbstractEnum.php b/src/PhpWord/Shared/AbstractEnum.php
index f2375d876e..cfbcf1e8a6 100644
--- a/src/PhpWord/Shared/AbstractEnum.php
+++ b/src/PhpWord/Shared/AbstractEnum.php
@@ -1,4 +1,5 @@
getConstants();
}
@@ -36,7 +40,7 @@ private static function getConstants()
}
/**
- * Returns all values for this enum
+ * Returns all values for this enum.
*
* @return array
*/
@@ -46,9 +50,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 +64,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 7008ac5d1d..17d2e1a05d 100644
--- a/src/PhpWord/Shared/Converter.php
+++ b/src/PhpWord/Shared/Converter.php
@@ -1,4 +1,5 @@
>
+ */
+ private $styles = [];
+
+ public function __construct(string $cssContent)
+ {
+ $this->cssContent = $cssContent;
+ }
+
+ public function process(): void
+ {
+ $cssContent = str_replace(["\r", "\n"], '', $this->cssContent);
+ preg_match_all('/(.+?)\s?\{\s?(.+?)\s?\}/', $cssContent, $cssExtracted);
+ // Check if there are x selectors and x rules
+ if (count($cssExtracted[1]) != count($cssExtracted[2])) {
+ return;
+ }
+
+ foreach ($cssExtracted[1] as $key => $selector) {
+ $rules = trim($cssExtracted[2][$key]);
+ $rules = explode(';', $rules);
+ foreach ($rules as $rule) {
+ if (empty($rule)) {
+ continue;
+ }
+ [$key, $value] = explode(':', trim($rule));
+ $this->styles[$this->sanitize($selector)][$this->sanitize($key)] = $this->sanitize($value);
+ }
+ }
+ }
+
+ public function getStyles(): array
+ {
+ return $this->styles;
+ }
+
+ public function getStyle(string $selector): array
+ {
+ $selector = $this->sanitize($selector);
+
+ return $this->styles[$selector] ?? [];
+ }
+
+ private function sanitize(string $value): string
+ {
+ return addslashes(trim($value));
+ }
+}
diff --git a/src/PhpWord/Shared/Drawing.php b/src/PhpWord/Shared/Drawing.php
new file mode 100644
index 0000000000..8af7da2ffc
--- /dev/null
+++ b/src/PhpWord/Shared/Drawing.php
@@ -0,0 +1,264 @@
+.
*
- * @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
- * @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,
* which could be applied when such an element occurs in the parseNode function.
*/
- self::$options = $options;
+ static::$options = $options;
// 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(["\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_'), array('<', '>', '&'), $html);
+ $html = str_replace(['_lt_', '_gt_', '_amp_', '_quot_'], ['<', '>', '&', '"'], $html);
if (false === $fullHTML) {
$html = '' . $html . '';
}
// Load DOM
- $orignalLibEntityLoader = libxml_disable_entity_loader(true);
- $dom = new \DOMDocument();
+ if (\PHP_VERSION_ID < 80000) {
+ $orignalLibEntityLoader = libxml_disable_entity_loader(true);
+ }
+ $dom = new DOMDocument();
$dom->preserveWhiteSpace = $preserveWhiteSpace;
$dom->loadXML($html);
- self::$xpath = new \DOMXPath($dom);
+ static::$xpath = new DOMXPath($dom);
$node = $dom->getElementsByTagName('body');
- self::parseNode($node->item(0), $element);
- libxml_disable_entity_loader($orignalLibEntityLoader);
+ static::parseNode($node->item(0), $element);
+ if (\PHP_VERSION_ID < 80000) {
+ libxml_disable_entity_loader($orignalLibEntityLoader);
+ }
}
/**
- * 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 array $styles is supplied, the inline style attributes are added to the already existing style
*
- * @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)
+ $attributeDir = $attributes->getNamedItem('dir');
+ $attributeDirValue = $attributeDir ? $attributeDir->nodeValue : '';
+ $bidi = $attributeDirValue === 'rtl';
foreach ($attributes as $attribute) {
- switch ($attribute->name) {
- case 'style':
- $styles = self::parseStyle($attribute, $styles);
- break;
+ $val = $attribute->value;
+ switch (strtolower($attribute->name)) {
case 'align':
- $styles['alignment'] = self::mapAlign($attribute->value);
+ $styles['alignment'] = self::mapAlign(trim($val), $bidi);
+
break;
case 'lang':
- $styles['lang'] = $attribute->value;
+ $styles['lang'] = $val;
+
break;
+ case 'width':
+ // tables, cells
+ $val = $val === 'auto' ? '100%' : $val;
+ if (false !== strpos($val, '%')) {
+ // e.g. or
+ $styles['width'] = (int) $val * 50;
+ $styles['unit'] = \PhpOffice\PhpWord\SimpleType\TblWidth::PERCENT;
+ } else {
+ // e.g. , where "2" = 2px (always pixels)
+ $styles['cellSpacing'] = Converter::pixelToTwip(self::convertHtmlSize($val));
+
+ break;
+ case 'bgcolor':
+ // tables, rows, cells e.g.
+ $styles['bgColor'] = self::convertRgb($val);
+
+ break;
+ case 'valign':
+ // cells e.g.
+ if (preg_match('#(?:top|bottom|middle|baseline)#i', $val, $matches)) {
+ $styles['valign'] = self::mapAlignVertical($matches[0]);
+ }
+
+ break;
+ }
+ }
+
+ $attributeIdentifier = $attributes->getNamedItem('id');
+ if ($attributeIdentifier && self::$css) {
+ $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->nodeValue), $styles);
}
+ $styles['className'] = $attributeClass->nodeValue;
+ }
+
+ $attributeStyle = $attributes->getNamedItem('style');
+ if ($attributeStyle) {
+ $styles = self::parseStyle($attributeStyle, $styles);
}
}
@@ -116,69 +186,79 @@ 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 \PhpOffice\PhpWord\Element\AbstractContainer $element object to add an element corresponding with the node
+ * @param DOMNode $node node to parse
+ * @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
*/
- protected static function parseNode($node, $element, $styles = array(), $data = array())
+ protected static function parseNode($node, $element, $styles = [], $data = []): void
{
+ if ($node->nodeName == 'style') {
+ self::$css = new Css($node->textContent);
+ self::$css->process();
+
+ return;
+ }
+
// 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),
- );
+ $nodes = [
+ // $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],
+ '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],
+ 'ruby' => ['Ruby', $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), $arguments);
+ $newElement = call_user_func_array(['PhpOffice\PhpWord\Shared\Html', $method], array_values($arguments));
// Retrieve back variables from arguments
foreach ($keys as $key) {
@@ -198,12 +278,12 @@ protected static function parseNode($node, $element, $styles = array(), $data =
/**
* Parse child nodes.
*
- * @param \DOMNode $node
- * @param \PhpOffice\PhpWord\Element\AbstractContainer $element
+ * @param DOMNode $node
+ * @param AbstractContainer|Row|Table $element
* @param array $styles
* @param array $data
*/
- private static function parseChildNodes($node, $element, $styles, $data)
+ protected static function parseChildNodes($node, $element, $styles, $data): void
{
if ('li' != $node->nodeName) {
$cNodes = $node->childNodes;
@@ -218,48 +298,74 @@ private static function parseChildNodes($node, $element, $styles, $data)
}
/**
- * Parse paragraph node
+ * Parse paragraph node.
*
- * @param \DOMNode $node
- * @param \PhpOffice\PhpWord\Element\AbstractContainer $element
+ * @param DOMNode $node
+ * @param AbstractContainer $element
* @param array &$styles
- * @return \PhpOffice\PhpWord\Element\TextRun
+ *
+ * @return \PhpOffice\PhpWord\Element\PageBreak|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']);
+ if (isset($styles['paragraph']['isPageBreak']) && $styles['paragraph']['isPageBreak']) {
+ return $element->addPageBreak();
+ }
- return $newElement;
+ return $element->addTextRun($styles['paragraph']);
}
/**
- * Parse heading node
+ * Parse input node.
*
- * @param \PhpOffice\PhpWord\Element\AbstractContainer $element
+ * @param DOMNode $node
+ * @param AbstractContainer $element
* @param array &$styles
+ */
+ protected static function parseInput($node, $element, &$styles): void
+ {
+ $attributes = $node->attributes;
+ if (null === $attributes->getNamedItem('type')) {
+ return;
+ }
+
+ $inputType = $attributes->getNamedItem('type')->nodeValue;
+ switch ($inputType) {
+ case 'checkbox':
+ $checked = ($checked = $attributes->getNamedItem('checked')) && $checked->nodeValue === 'true' ? true : false;
+ $textrun = $element->addTextRun($styles['paragraph']);
+ $textrun->addFormField('checkbox')->setValue($checked);
+
+ break;
+ }
+ }
+
+ /**
+ * Parse heading node.
+ *
* @param string $argument1 Name of heading style
- * @return \PhpOffice\PhpWord\Element\TextRun
*
* @todo Think of a clever way of defining header styles, now it is only based on the assumption, that
* Heading1 - Heading6 are already defined somewhere
*/
- private static function parseHeading($element, &$styles, $argument1)
+ 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);
}
/**
- * Parse text node
+ * Parse text node.
*
- * @param \DOMNode $node
- * @param \PhpOffice\PhpWord\Element\AbstractContainer $element
+ * @param DOMNode $node
+ * @param AbstractContainer $element
* @param array &$styles
*/
- private static function parseText($node, $element, &$styles)
+ protected static function parseText($node, $element, &$styles): void
{
$styles['font'] = self::recursiveParseStylesInHierarchy($node, $styles['font']);
@@ -268,92 +374,98 @@ private 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
*/
- private 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
*/
- private 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 \PhpOffice\PhpWord\Element\AbstractContainer $element
+ * @param DOMNode $node
+ * @param AbstractContainer $element
* @param array &$styles
+ *
* @return Table $element
*
* @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']);
$newElement = $element->addTable($elementStyles);
- // $attributes = $node->attributes;
- // if ($attributes->getNamedItem('width') !== null) {
- // $newElement->setWidth($attributes->getNamedItem('width')->value);
- // }
+ // Add style name from CSS Class
+ if (isset($elementStyles['className'])) {
+ $newElement->getStyle()->setStyleName($elementStyles['className']);
+ }
- // 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')) {
+ $border = (int) $attributes->getNamedItem('border')->nodeValue;
+ $newElement->getStyle()->setBorderSize(Converter::pixelToTwip($border));
+ }
return $newElement;
}
/**
- * Parse a table row
+ * Parse a table row.
*
- * @param \DOMNode $node
- * @param \PhpOffice\PhpWord\Element\Table $element
+ * @param DOMNode $node
+ * @param Table $element
* @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') {
$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);
}
/**
- * Parse table cell
+ * Parse table cell.
*
- * @param \DOMNode $node
- * @param \PhpOffice\PhpWord\Element\Table $element
+ * @param DOMNode $node
+ * @param Table $element
* @param array &$styles
- * @return \PhpOffice\PhpWord\Element\Cell|\PhpOffice\PhpWord\Element\TextRun $element
+ *
+ * @return \PhpOffice\PhpWord\Element\Cell|TextRun $element
*/
- private static function parseCell($node, $element, &$styles)
+ protected static function parseCell($node, $element, &$styles)
{
$cellStyles = self::recursiveParseStylesInHierarchy($node, $styles['cell']);
@@ -361,24 +473,27 @@ private static function parseCell($node, $element, &$styles)
if (!empty($colspan)) {
$cellStyles['gridSpan'] = $colspan - 0;
}
- $cell = $element->addCell(null, $cellStyles);
+
+ // set cell width to control column widths
+ $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']));
+ return $cell->addTextRun(self::filterOutNonInheritedStyles(self::parseInlineStyle($node, $styles['paragraph'])));
}
return $cell;
}
/**
- * 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
*/
- private static function shouldAddTextRun(\DOMNode $node)
+ 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;
}
@@ -389,38 +504,96 @@ private 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
*/
- 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);
+ $parentStyle = [];
if ($node->parentNode != null && XML_ELEMENT_NODE == $node->parentNode->nodeType) {
- $style = self::recursiveParseStylesInHierarchy($node->parentNode, $style);
+ $parentStyle = self::recursiveParseStylesInHierarchy($node->parentNode, []);
+ }
+ if ($node->nodeName === '#text') {
+ $parentStyle = array_merge($parentStyle, $style);
+ } else {
+ $parentStyle = self::filterOutNonInheritedStyles($parentStyle);
}
+ $style = self::parseInlineStyle($node, $parentStyle);
return $style;
}
/**
- * Parse list node
+ * Removes non-inherited styles from array.
+ */
+ protected static function filterOutNonInheritedStyles(array $styles)
+ {
+ $nonInheritedStyles = [
+ '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.
*
- * @param \DOMNode $node
- * @param \PhpOffice\PhpWord\Element\AbstractContainer $element
+ * @param DOMNode $node
+ * @param AbstractContainer $element
* @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'])) {
- $data['listdepth']++;
+ ++$data['listdepth'];
} 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);
+ }
+ $type = $type ? self::mapListType($type) : null;
+ if ($type) {
+ $level->setFormat($type);
+ }
}
if ($node->parentNode->nodeName === 'li') {
return $element->getParent();
@@ -429,55 +602,56 @@ 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(
- '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 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'),
- ),
- );
- }
-
- /**
- * Parse list item node
- *
- * @param \DOMNode $node
- * @param \PhpOffice\PhpWord\Element\AbstractContainer $element
+ 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 [
+ 'type' => 'hybridMultilevel',
+ 'levels' => [
+ ['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'],
+ ],
+ ];
+ }
+
+ /**
+ * Parse list item node.
+ *
+ * @param DOMNode $node
+ * @param AbstractContainer $element
* @param array &$styles
* @param array $data
*
* @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): void
{
$cNodes = $node->childNodes;
if (!empty($cNodes)) {
@@ -489,59 +663,85 @@ private static function parseListItem($node, $element, &$styles, $data)
}
/**
- * Parse style
+ * Parse style.
*
- * @param \DOMAttr $attribute
- * @param array $styles
- * @return array
+ * @param DOMNode $attribute
*/
- private 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) {
- list($cKey, $cValue) = array_pad(explode(':', $property, 2), 2, null);
- $cValue = trim($cValue);
- switch (trim($cKey)) {
+ [$cKey, $cValue] = array_pad(explode(':', $property, 2), 2, null);
+ $selectors[strtolower(trim($cKey))] = trim($cValue ?? '');
+ }
+
+ return self::parseStyleDeclarations($selectors, $styles);
+ }
+
+ protected static function parseStyleDeclarations(array $selectors, array $styles): array
+ {
+ $bidi = ($selectors['direction'] ?? '') === 'rtl';
+ foreach ($selectors as $property => $value) {
+ switch ($property) {
case 'text-decoration':
- switch ($cValue) {
+ switch ($value) {
case 'underline':
$styles['underline'] = 'single';
+
break;
case 'line-through':
$styles['strikethrough'] = true;
+
break;
}
+
break;
case 'text-align':
- $styles['alignment'] = self::mapAlign($cValue);
+ $styles['alignment'] = self::mapAlign($value, $bidi);
+
+ break;
+ case 'ruby-align':
+ $styles['rubyAlignment'] = self::mapRubyAlign($value);
+
break;
case 'display':
- $styles['hidden'] = $cValue === 'none' || $cValue === 'hidden';
+ $styles['hidden'] = $value === 'none' || $value === 'hidden';
+
break;
case 'direction':
- $styles['rtl'] = $cValue === 'rtl';
+ $styles['rtl'] = $value === 'rtl';
+ $styles['bidi'] = $value === 'rtl';
+
break;
case 'font-size':
- $styles['size'] = Converter::cssToPoint($cValue);
+ $styles['size'] = Converter::cssToPoint($value);
+
break;
case 'font-family':
- $cValue = array_map('trim', explode(',', $cValue));
- $styles['name'] = ucwords($cValue[0]);
+ $value = array_map('trim', explode(',', $value));
+ $styles['name'] = ucwords($value[0]);
+
break;
case 'color':
- $styles['color'] = trim($cValue, '#');
+ $styles['color'] = self::convertRgb($value);
+
break;
case 'background-color':
- $styles['bgColor'] = trim($cValue, '#');
+ $styles['bgColor'] = self::convertRgb($value);
+
break;
case 'line-height':
- $matches = array();
- if (preg_match('/([0-9]+\.?[0-9]*[a-z]+)/', $cValue, $matches)) {
+ $matches = [];
+ if ($value === 'normal' || $value === 'inherit') {
+ $spacingLineRule = \PhpOffice\PhpWord\SimpleType\LineSpacingRule::AUTO;
+ $spacing = 0;
+ } elseif (preg_match('/([0-9]+\.?[0-9]*[a-z]+)/', $value, $matches)) {
//matches number with a unit, e.g. 12px, 15pt, 20mm, ...
$spacingLineRule = \PhpOffice\PhpWord\SimpleType\LineSpacingRule::EXACT;
$spacing = Converter::cssToTwip($matches[1]);
- } elseif (preg_match('/([0-9]+)%/', $cValue, $matches)) {
+ } elseif (preg_match('/([0-9]+)%/', $value, $matches)) {
//matches percentages
$spacingLineRule = \PhpOffice\PhpWord\SimpleType\LineSpacingRule::AUTO;
//we are subtracting 1 line height because the Spacing writer is adding one line
@@ -550,64 +750,184 @@ private static function parseStyle($attribute, $styles)
//any other, wich is a multiplier. E.g. 1.2
$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 = ($value * Paragraph::LINE_HEIGHT) - Paragraph::LINE_HEIGHT;
}
$styles['spacingLineRule'] = $spacingLineRule;
$styles['line-spacing'] = $spacing;
+
break;
case 'letter-spacing':
- $styles['letter-spacing'] = Converter::cssToTwip($cValue);
+ $styles['letter-spacing'] = Converter::cssToTwip($value);
+
break;
case 'text-indent':
- $styles['indentation']['firstLine'] = Converter::cssToTwip($cValue);
+ $styles['indentation']['firstLine'] = Converter::cssToTwip($value);
+
break;
case 'font-weight':
$tValue = false;
- if (preg_match('#bold#', $cValue)) {
+ if (preg_match('#bold#', $value)) {
$tValue = true; // also match bolder
}
$styles['bold'] = $tValue;
+
break;
case 'font-style':
$tValue = false;
- if (preg_match('#(?:italic|oblique)#', $cValue)) {
+ if (preg_match('#(?:italic|oblique)#', $value)) {
$tValue = true;
}
$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);
+ $styles['spaceBefore'] = $value;
+ $styles['spaceAfter'] = $value;
+
break;
case 'margin-top':
- $styles['spaceBefore'] = Converter::cssToPoint($cValue);
+ // BC change: up to ver. 0.17.0 incorrectly converted to points - Converter::cssToPoint($value)
+ $styles['spaceBefore'] = Converter::cssToTwip($value);
+
break;
case 'margin-bottom':
- $styles['spaceAfter'] = Converter::cssToPoint($cValue);
+ // BC change: up to ver. 0.17.0 incorrectly converted to points - Converter::cssToPoint($value)
+ $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, $cValue);
+ self::mapBorderColor($styles, $value);
+
break;
case 'border-width':
- $styles['borderSize'] = Converter::cssToPoint($cValue);
+ $styles['borderSize'] = Converter::cssToPoint($value);
+
break;
case 'border-style':
- $styles['borderStyle'] = self::mapBorderStyle($cValue);
+ $styles['borderStyle'] = self::mapBorderStyle($value);
+
break;
case 'width':
- if (preg_match('/([0-9]+[a-z]+)/', $cValue, $matches)) {
+ if (preg_match('/([0-9]+[a-z]+)/', $value, $matches)) {
$styles['width'] = Converter::cssToTwip($matches[1]);
$styles['unit'] = \PhpOffice\PhpWord\SimpleType\TblWidth::TWIP;
- } elseif (preg_match('/([0-9]+)%/', $cValue, $matches)) {
+ } elseif (preg_match('/([0-9]+)%/', $value, $matches)) {
$styles['width'] = $matches[1] * 50;
$styles['unit'] = \PhpOffice\PhpWord\SimpleType\TblWidth::PERCENT;
- } elseif (preg_match('/([0-9]+)/', $cValue, $matches)) {
+ } elseif (preg_match('/([0-9]+)/', $value, $matches)) {
$styles['width'] = $matches[1];
$styles['unit'] = \PhpOffice\PhpWord\SimpleType\TblWidth::AUTO;
}
+
+ break;
+ case 'height':
+ $styles['height'] = Converter::cssToTwip($value);
+ $styles['exactHeight'] = true;
+
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]+)/', $value, $matches)) {
+ if (false !== strpos($property, '-')) {
+ $tmp = explode('-', $property);
+ $which = $tmp[1];
+ $which = ucfirst($which); // e.g. bottom -> Bottom
+ } else {
+ $which = '';
+ }
+ // 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 = (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], '#');
+ $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', $value, $matches)) {
+ $styles['valign'] = self::mapAlignVertical($matches[0]);
+ }
+
+ break;
+ case 'page-break-after':
+ if ($value == 'always') {
+ $styles['isPageBreak'] = true;
}
+
break;
}
}
@@ -616,57 +936,60 @@ private static function parseStyle($attribute, $styles)
}
/**
- * Parse image node
+ * Parse image node.
*
- * @param \DOMNode $node
- * @param \PhpOffice\PhpWord\Element\AbstractContainer $element
+ * @param DOMNode $node
+ * @param AbstractContainer $element
*
* @return \PhpOffice\PhpWord\Element\Image
- **/
- private static function parseImage($node, $element)
+ */
+ 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['width'] = self::convertHtmlSize($attribute->value);
$style['unit'] = \PhpOffice\PhpWord\Style\Image::UNIT_PX;
+
break;
case 'height':
- $height = $attribute->value;
- $style['height'] = $height;
+ $style['height'] = self::convertHtmlSize($attribute->value);
$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') {
$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;
}
+
break;
}
}
}
+
break;
}
}
@@ -674,33 +997,37 @@ private 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);
+ 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);
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];
+ $src = $tmpDir . uniqid();
+ if (isset($match[1])) {
+ $src .= '.' . $match[1];
+ }
$ifp = fopen($src, 'wb');
@@ -714,19 +1041,20 @@ private 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
*/
- private static function mapBorderStyle($cssBorderStyle)
+ protected static function mapBorderStyle($cssBorderStyle)
{
switch ($cssBorderStyle) {
case 'none':
@@ -739,73 +1067,264 @@ private static function mapBorderStyle($cssBorderStyle)
}
}
- private 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
+ * @param bool $bidi
+ *
+ * @return null|string
*/
- private 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;
}
}
/**
- * Parse line break
+ * 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.
+ *
+ * @param string $alignment
*
- * @param \PhpOffice\PhpWord\Element\AbstractContainer $element
+ * @return null|string
*/
- private static function parseLineBreak($element)
+ 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:
+ // @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 '';
+ }
+ }
+
+ /**
+ * 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.
+ *
+ * @param AbstractContainer $element
+ */
+ protected static function parseLineBreak($element): void
{
$element->addTextBreak();
}
/**
- * Parse link node
+ * Parse link node.
*
- * @param \DOMNode $node
- * @param \PhpOffice\PhpWord\Element\AbstractContainer $element
+ * @param DOMNode $node
+ * @param 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) {
switch ($attribute->name) {
case 'href':
$target = $attribute->value;
+
break;
}
}
$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);
}
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 AbstractContainer $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 + ['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
+ }
+
+ /**
+ * 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) {
+ return sprintf('%02X%02X%02X', $matches[1], $matches[2], $matches[3]);
+ }
+
+ 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/src/PhpWord/Shared/Microsoft/PasswordEncoder.php b/src/PhpWord/Shared/Microsoft/PasswordEncoder.php
new file mode 100644
index 0000000000..4762cc7104
--- /dev/null
+++ b/src/PhpWord/Shared/Microsoft/PasswordEncoder.php
@@ -0,0 +1,252 @@
+ 4) ? 0xFFFFFFFF : -1;
+ private const HIGH_ORDER_BIT = (PHP_INT_SIZE > 4) ? 0x80000000 : PHP_INT_MIN;
+
+ /**
+ * 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 = [
+ 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,
+ 0x84C0,
+ 0x110C,
+ 0x0E10,
+ 0xF1CE,
+ 0x313E,
+ 0x1872,
+ 0xE139,
+ 0xD40F,
+ 0x84F9,
+ 0x280C,
+ 0xA96A,
+ 0x4EC3,
+ ];
+
+ 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.
+ *
+ * @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');
+ 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));
+
+ 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 & 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');
+
+ // 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 & self::ALL_ONE_BITS;
+
+ if ($value & self::HIGH_ORDER_BIT) {
+ $value = -((~$value & self::ALL_ONE_BITS) + 1);
+ }
+
+ return $value;
+ }
+}
diff --git a/src/PhpWord/Shared/OLERead.php b/src/PhpWord/Shared/OLERead.php
index 2e6a899e57..d4399d6fb7 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,48 @@ 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;
+ 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
@@ -75,7 +84,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 +121,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 +153,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 +163,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 +179,7 @@ public function read($sFileName)
/**
* Extract binary stream data
*
+ * @param mixed $stream
* @return string
*/
public function getStream($stream)
@@ -189,7 +199,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 +211,7 @@ public function getStream($stream)
}
if ($numBlocks == 0) {
- return '';// @codeCoverageIgnore
+ return ''; // @codeCoverageIgnore
}
$block = $this->props[$stream]['startBlock'];
@@ -209,7 +219,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 +239,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 +259,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 +270,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 +328,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;
}
}
diff --git a/src/PhpWord/Shared/PCLZip/pclzip.lib.php b/src/PhpWord/Shared/PCLZip/pclzip.lib.php
index 3fbc932744..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]);
@@ -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/src/PhpWord/Shared/Text.php b/src/PhpWord/Shared/Text.php
new file mode 100644
index 0000000000..251764b3dd
--- /dev/null
+++ b/src/PhpWord/Shared/Text.php
@@ -0,0 +1,259 @@
+)
+ * 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 int $decimals
+ *
+ * @return string
+ */
+ public static function numberFormat($number, $decimals)
+ {
+ return number_format($number, $decimals, '.', '');
+ }
+
+ /**
+ * @param int $dec
+ *
+ * @see 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 bool
+ */
+ public static function isUTF8($value = '')
+ {
+ return is_string($value) && ($value === '' || preg_match('/^./su', $value) == 1);
+ }
+
+ /**
+ * Return UTF8 encoded value.
+ *
+ * @param null|string $value
+ *
+ * @return ?string
+ */
+ 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;
+ }
+
+ /**
+ * 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
+ * @see http://www.randomchaos.com/documents/?source=php_and_unicode
+ */
+ public static function utf8ToUnicode($text)
+ {
+ $unicode = [];
+ $values = [];
+ $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 = [];
+ $lookingFor = 1;
+ }
+ }
+ }
+
+ return $unicode;
+ }
+
+ /**
+ * Returns entites from unicode array.
+ *
+ * @param array $unicode
+ *
+ * @return string
+ *
+ * @since 0.11.0
+ * @see 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 (null !== $value) {
+ if (substr($value, 0, 1) == '_') {
+ $value = substr($value, 1);
+ }
+ }
+
+ return $value;
+ }
+}
diff --git a/src/PhpWord/Shared/Validate.php b/src/PhpWord/Shared/Validate.php
new file mode 100644
index 0000000000..faa7df0db4
--- /dev/null
+++ b/src/PhpWord/Shared/Validate.php
@@ -0,0 +1,77 @@
+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();
+
+ if ($content === false) {
+ return false;
+ }
+
+ return $this->getDomFromString($content);
+ }
+
+ /**
+ * Get DOMDocument from content string.
+ *
+ * @param string $content
+ *
+ * @return DOMDocument
+ */
+ public function getDomFromString($content)
+ {
+ if (\PHP_VERSION_ID < 80000) {
+ $originalLibXMLEntityValue = libxml_disable_entity_loader(true);
+ }
+ $this->dom = new DOMDocument();
+ $this->dom->loadXML($content);
+ if (\PHP_VERSION_ID < 80000) {
+ libxml_disable_entity_loader($originalLibXMLEntityValue);
+ }
+
+ return $this->dom;
+ }
+
+ /**
+ * Get elements.
+ *
+ * @param string $path
+ *
+ * @return DOMNodeList
+ */
+ public function getElements($path, ?DOMElement $contextNode = null)
+ {
+ if ($this->dom === null) {
+ return new DOMNodeList(); // @phpstan-ignore-line
+ }
+ if ($this->xpath === null) {
+ $this->xpath = new DOMXpath($this->dom);
+ }
+
+ $result = @$this->xpath->query($path, $contextNode);
+
+ return empty($result) ? new DOMNodeList() : $result; // @phpstan-ignore-line
+ }
+
+ /**
+ * 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
+ */
+ 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
+ *
+ * @return null|DOMElement
+ */
+ 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 string $path
+ *
+ * @return null|string
+ */
+ 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
+ *
+ * @return null|string
+ */
+ 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
+ *
+ * @return int
+ */
+ public function countElements($path, ?DOMElement $contextNode = null)
+ {
+ $elements = $this->getElements($path, $contextNode);
+
+ return $elements->length;
+ }
+
+ /**
+ * Element exists.
+ *
+ * @param string $path
+ *
+ * @return bool
+ */
+ 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
new file mode 100644
index 0000000000..441eac05f0
--- /dev/null
+++ b/src/PhpWord/Shared/XMLWriter.php
@@ -0,0 +1,184 @@
+openMemory();
+ } else {
+ if (!$pTemporaryStorageDir || !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 array|string $attributes
+ * @param string $value
+ */
+ public function writeElementBlock($element, $attributes, $value = null): void
+ {
+ $this->startElement($element);
+ if (!is_array($attributes)) {
+ $attributes = [$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
+ */
+ public function writeElementIf($condition, $element, $attribute = null, $value = null): void
+ {
+ if ($condition == true) {
+ if (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
+ */
+ public function writeAttributeIf($condition, $attribute, $value): void
+ {
+ if ($condition == true) {
+ $this->writeAttribute($attribute, $value);
+ }
+ }
+
+ /**
+ * @param string $name
+ * @param mixed $value
+ */
+ public function writeAttribute($name, $value): bool
+ {
+ if (is_float($value)) {
+ $value = json_encode($value);
+ }
+
+ return parent::writeAttribute($name, $value ?? '');
+ }
+}
diff --git a/src/PhpWord/Shared/ZipArchive.php b/src/PhpWord/Shared/ZipArchive.php
index bc71e74b17..462206c7f5 100644
--- a/src/PhpWord/Shared/ZipArchive.php
+++ b/src/PhpWord/Shared/ZipArchive.php
@@ -1,4 +1,5 @@
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
// 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;
}
@@ -149,18 +161,19 @@ public function open($filename, $flags = null)
}
/**
- * Close the active archive
- *
- * @throws \PhpOffice\PhpWord\Exception\Exception
+ * 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}: ");
}
}
@@ -169,11 +182,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)
@@ -190,10 +205,11 @@ 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
+ *
+ * @return bool|string $contents File string contents
*/
public function getFromName($filename)
{
@@ -211,15 +227,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
@@ -228,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))), '/');
@@ -255,58 +274,64 @@ 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;
}
/**
- * 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);
+ $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');
- fwrite($handle, $contents);
- fclose($handle);
+ $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;
}
/**
- * 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;
@@ -314,7 +339,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);
@@ -328,14 +353,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;
@@ -347,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'];
}
@@ -355,15 +381,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])) {
@@ -374,14 +402,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
+ *
+ * @return false|int
*/
public function pclzipLocateName($filename)
{
- /** @var \PclZip $zip Type hint */
+ /** @var PclZip $zip Type hint */
$zip = $this->zip;
$list = $zip->listContent();
$listCount = count($list);
@@ -390,10 +419,22 @@ public function pclzipLocateName($filename)
if (strtolower($list[$i]['filename']) == strtolower($filename) ||
strtolower($list[$i]['stored_filename']) == strtolower($filename)) {
$listIndex = $i;
+
break;
}
}
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/SimpleType/Border.php b/src/PhpWord/SimpleType/Border.php
new file mode 100644
index 0000000000..acd1c1a1b1
--- /dev/null
+++ b/src/PhpWord/SimpleType/Border.php
@@ -0,0 +1,58 @@
+aliases[$key])) {
$key = $this->aliases[$key];
}
+
+ if ($key === 'align') {
+ $key = 'alignment';
+ }
+
$method = 'set' . Text::removeUnderscorePrefix($key);
if (method_exists($this, $method)) {
$this->$method($value);
@@ -171,12 +185,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,11 +201,12 @@ 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)
+ * @param ?string $value
+ * @param string $default
+ *
+ * @return string
*/
protected function setNonEmptyVal($value, $default)
{
@@ -202,10 +218,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 +235,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 +252,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 int|null $value
- * @param int|null $default
- * @return int|null
+ * @param null|float|int|string $value
+ * @param null|int $default
+ *
+ * @return null|int
*/
protected function setIntVal($value, $default = null)
{
@@ -255,11 +274,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 +294,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,18 +314,18 @@ 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)
+ protected function setObjectVal($value, string $styleName, &$style)
{
- $styleClass = substr(get_class($this), 0, strrpos(get_class($this), '\\')) . '\\' . $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();
}
@@ -319,11 +338,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)
@@ -335,20 +355,4 @@ protected function setPairedVal(&$property, &$pairProperty, $value)
return $this;
}
-
- /**
- * Set style using associative array
- *
- * @deprecated 0.11.0
- *
- * @param array $style
- *
- * @return self
- *
- * @codeCoverageIgnore
- */
- public function setArrayStyle(array $style = array())
- {
- return $this->setStyleByArray($style);
- }
}
diff --git a/src/PhpWord/Style/Border.php b/src/PhpWord/Style/Border.php
index d032d07faa..722e09931a 100644
--- a/src/PhpWord/Style/Border.php
+++ b/src/PhpWord/Style/Border.php
@@ -1,4 +1,5 @@
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 +170,25 @@ public function setBorderSize($value = null)
}
/**
- * Get border color
+ * Get border color.
*
- * @return string[]
+ * @return array
*/
public function getBorderColor()
{
- return array(
+ return [
$this->getBorderTopColor(),
$this->getBorderLeftColor(),
$this->getBorderRightColor(),
$this->getBorderBottomColor(),
- );
+ ];
}
/**
- * Set border color
+ * Set border color.
+ *
+ * @param null|string $value
*
- * @param string $value
* @return self
*/
public function setBorderColor($value = null)
@@ -169,24 +202,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 +234,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 +244,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,9 +258,9 @@ public function setBorderTopSize($value = null)
}
/**
- * Get border top color
+ * Get border top color.
*
- * @return string
+ * @return null|string
*/
public function getBorderTopColor()
{
@@ -233,9 +268,10 @@ public function getBorderTopColor()
}
/**
- * Set border top color
+ * Set border top color.
+ *
+ * @param null|string $value
*
- * @param string $value
* @return self
*/
public function setBorderTopColor($value = null)
@@ -246,7 +282,7 @@ public function setBorderTopColor($value = null)
}
/**
- * Get border top style
+ * Get border top style.
*
* @return string
*/
@@ -256,9 +292,10 @@ public function getBorderTopStyle()
}
/**
- * Set border top Style
+ * Set border top Style.
*
* @param string $value
+ *
* @return self
*/
public function setBorderTopStyle($value = null)
@@ -269,9 +306,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 +316,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,9 +330,9 @@ public function setBorderLeftSize($value = null)
}
/**
- * Get border left color
+ * Get border left color.
*
- * @return string
+ * @return null|string
*/
public function getBorderLeftColor()
{
@@ -302,9 +340,10 @@ public function getBorderLeftColor()
}
/**
- * Set border left color
+ * Set border left color.
+ *
+ * @param null|string $value
*
- * @param string $value
* @return self
*/
public function setBorderLeftColor($value = null)
@@ -315,7 +354,7 @@ public function setBorderLeftColor($value = null)
}
/**
- * Get border left style
+ * Get border left style.
*
* @return string
*/
@@ -325,9 +364,10 @@ public function getBorderLeftStyle()
}
/**
- * Set border left style
+ * Set border left style.
*
* @param string $value
+ *
* @return self
*/
public function setBorderLeftStyle($value = null)
@@ -338,9 +378,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 +388,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,9 +402,9 @@ public function setBorderRightSize($value = null)
}
/**
- * Get border right color
+ * Get border right color.
*
- * @return string
+ * @return null|string
*/
public function getBorderRightColor()
{
@@ -371,9 +412,10 @@ public function getBorderRightColor()
}
/**
- * Set border right color
+ * Set border right color.
+ *
+ * @param null|string $value
*
- * @param string $value
* @return self
*/
public function setBorderRightColor($value = null)
@@ -384,7 +426,7 @@ public function setBorderRightColor($value = null)
}
/**
- * Get border right style
+ * Get border right style.
*
* @return string
*/
@@ -394,9 +436,10 @@ public function getBorderRightStyle()
}
/**
- * Set border right style
+ * Set border right style.
*
* @param string $value
+ *
* @return self
*/
public function setBorderRightStyle($value = null)
@@ -407,9 +450,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 +460,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,9 +474,9 @@ public function setBorderBottomSize($value = null)
}
/**
- * Get border bottom color
+ * Get border bottom color.
*
- * @return string
+ * @return null|string
*/
public function getBorderBottomColor()
{
@@ -440,9 +484,10 @@ public function getBorderBottomColor()
}
/**
- * Set border bottom color
+ * Set border bottom color.
+ *
+ * @param null|string $value
*
- * @param string $value
* @return self
*/
public function setBorderBottomColor($value = null)
@@ -453,7 +498,7 @@ public function setBorderBottomColor($value = null)
}
/**
- * Get border bottom style
+ * Get border bottom style.
*
* @return string
*/
@@ -463,9 +508,10 @@ public function getBorderBottomStyle()
}
/**
- * Set border bottom style
+ * Set border bottom style.
*
* @param string $value
+ *
* @return self
*/
public function setBorderBottomStyle($value = null)
@@ -476,7 +522,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
*/
@@ -486,4 +532,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/Cell.php b/src/PhpWord/Style/Cell.php
index 1276b5b59a..e2b59f417d 100644
--- a/src/PhpWord/Style/Cell.php
+++ b/src/PhpWord/Style/Cell.php
@@ -1,4 +1,5 @@
vAlign = null;
+
+ return $this;
+ }
+
VerticalJc::validate($value);
$this->vAlign = $this->setEnumVal($value, VerticalJc::values(), $this->vAlign);
@@ -173,21 +188,29 @@ 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,
+ 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;
}
/**
- * Get background
+ * Get background.
*
* @return string
*/
@@ -201,14 +224,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 +246,10 @@ public function getGridSpan()
}
/**
- * Set grid span (colspan)
+ * Set grid span (colspan).
*
* @param int $value
+ *
* @return self
*/
public function setGridSpan($value = null)
@@ -237,7 +262,7 @@ public function setGridSpan($value = null)
/**
* Get vertical merge (rowspan).
*
- * @return string
+ * @return null|string
*/
public function getVMerge()
{
@@ -245,23 +270,30 @@ public function getVMerge()
}
/**
- * Set vertical merge (rowspan)
+ * Set vertical merge (rowspan).
+ *
+ * @param null|string $value
*
- * @param string $value
* @return self
*/
public function setVMerge($value = null)
{
- $enum = array(self::VMERGE_RESTART, self::VMERGE_CONTINUE);
+ if ($value === null) {
+ $this->vMerge = null;
+
+ return $this;
+ }
+
+ $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
+ * @return Shading
*/
public function getShading()
{
@@ -269,9 +301,10 @@ public function getShading()
}
/**
- * Set shading
+ * Set shading.
*
* @param mixed $value
+ *
* @return self
*/
public function setShading($value = null)
@@ -282,9 +315,9 @@ public function setShading($value = null)
}
/**
- * Get cell width
+ * Get cell width.
*
- * @return int
+ * @return ?int
*/
public function getWidth()
{
@@ -292,20 +325,21 @@ public function getWidth()
}
/**
- * Set cell width
+ * Set cell width.
*
* @param int $value
+ *
* @return self
*/
public function setWidth($value)
{
- $this->setIntVal($value);
+ $this->width = $this->setIntVal($value);
return $this;
}
/**
- * Get width unit
+ * Get width unit.
*
* @return string
*/
@@ -315,26 +349,112 @@ 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
+ * Set noWrap.
+ */
+ public function setNoWrap(bool $value): self
+ {
+ $this->noWrap = $this->setBoolVal($value, true);
+
+ return $this;
+ }
+
+ /**
+ * Get noWrap.
+ */
+ public function getNoWrap(): bool
+ {
+ return $this->noWrap;
+ }
+
+ /**
+ * Get style padding-top.
+ */
+ public function getPaddingTop(): ?int
+ {
+ return $this->paddingTop;
+ }
+
+ /**
+ * Set style padding-top.
*
- * @deprecated 0.10.0
+ * @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.
*
- * @codeCoverageIgnore
+ * @return $this
*/
- public function getDefaultBorderColor()
+ public function setPaddingBottom(int $value): self
{
- return self::DEFAULT_BORDER_COLOR;
+ $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/Style/Chart.php b/src/PhpWord/Style/Chart.php
index 06b4829c3c..3773565ce9 100644
--- a/src/PhpWord/Style/Chart.php
+++ b/src/PhpWord/Style/Chart.php
@@ -1,4 +1,5 @@
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
*/
@@ -95,7 +104,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
*/
@@ -113,45 +122,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
*/
@@ -161,9 +170,10 @@ public function getWidth()
}
/**
- * Set width
+ * Set width.
*
* @param int $value
+ *
* @return self
*/
public function setWidth($value = null)
@@ -174,7 +184,7 @@ public function setWidth($value = null)
}
/**
- * Get height
+ * Get height.
*
* @return int
*/
@@ -184,9 +194,10 @@ public function getHeight()
}
/**
- * Set height
+ * Set height.
*
* @param int $value
+ *
* @return self
*/
public function setHeight($value = null)
@@ -197,7 +208,7 @@ public function setHeight($value = null)
}
/**
- * Is 3D
+ * Is 3D.
*
* @return bool
*/
@@ -207,9 +218,10 @@ public function is3d()
}
/**
- * Set 3D
+ * Set 3D.
*
* @param bool $value
+ *
* @return self
*/
public function set3d($value = true)
@@ -233,8 +245,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;
@@ -242,7 +256,7 @@ public function setColors($value = array())
}
/**
- * Get the chart title
+ * Get the chart title.
*
* @return string
*/
@@ -252,9 +266,11 @@ public function getTitle()
}
/**
- * Set the chart title
+ * Set the chart title.
*
* @param string $value
+ *
+ * @return self
*/
public function setTitle($value = null)
{
@@ -264,7 +280,7 @@ public function setTitle($value = null)
}
/**
- * Get chart legend visibility
+ * Get chart legend visibility.
*
* @return bool
*/
@@ -274,9 +290,11 @@ public function isShowLegend()
}
/**
- * Set chart legend visibility
+ * Set chart legend visibility.
*
* @param bool $value
+ *
+ * @return self
*/
public function setShowLegend($value = false)
{
@@ -285,6 +303,38 @@ 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
+ * "tr" - top right of chart.
+ *
+ * default: right
+ *
+ * @param string $legendPosition
+ *
+ * @return self
+ */
+ public function setLegendPosition($legendPosition = 'r')
+ {
+ $enum = ['r', 'b', 't', 'l', 'tr'];
+ $this->legendPosition = $this->setEnumVal($legendPosition, $enum, $this->legendPosition);
+
+ return $this;
+ }
+
/*
* Show labels for axis
*
@@ -296,9 +346,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)
@@ -309,7 +360,7 @@ public function setShowAxisLabels($value = true)
}
/**
- * get the list of options for data labels
+ * get the list of options for data labels.
*
* @return array
*/
@@ -324,11 +375,14 @@ 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])) {
- $this->dataLabelOptions[$option] = $this->setBoolVal($values[$option], $this->dataLabelOptions[$option]);
+ $this->dataLabelOptions[$option] = $this->setBoolVal(
+ $values[$option],
+ $this->dataLabelOptions[$option]
+ );
}
}
}
@@ -344,9 +398,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)
@@ -357,7 +412,7 @@ public function setShowGridY($value = true)
}
/**
- * Get the categoryLabelPosition setting
+ * Get the categoryLabelPosition setting.
*
* @return string
*/
@@ -371,21 +426,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
*/
@@ -399,21 +455,19 @@ 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
- *
- * @param string
- * @param mixed $labelPosition
+ * "high" - sets labels above the graph.
*/
- public function setValueLabelPosition($labelPosition)
+ public function setValueLabelPosition(string $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()
@@ -422,7 +476,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)
@@ -433,7 +488,8 @@ public function setCategoryAxisTitle($axisTitle)
}
/**
- * Get the valueAxisTitle
+ * Get the valueAxisTitle.
+ *
* @return string
*/
public function getValueAxisTitle()
@@ -442,7 +498,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)
@@ -458,17 +515,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
*/
@@ -478,9 +536,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..c31c51eb4f 100644
--- a/src/PhpWord/Style/Extrusion.php
+++ b/src/PhpWord/Style/Extrusion.php
@@ -1,4 +1,5 @@
setStyleByArray($style);
}
/**
- * Get type
+ * Get type.
*
* @return string
*/
@@ -68,21 +69,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 +94,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..f9dfe5a1cb 100644
--- a/src/PhpWord/Style/Fill.php
+++ b/src/PhpWord/Style/Fill.php
@@ -1,4 +1,5 @@
setStyleByArray($style);
}
/**
- * Get color
+ * Get color.
*
* @return string
*/
@@ -55,9 +56,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..f03e8899d1 100644
--- a/src/PhpWord/Style/Font.php
+++ b/src/PhpWord/Style/Font.php
@@ -1,4 +1,5 @@
'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
+ * @var null|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
+ * @var Paragraph
*/
private $paragraph;
/**
- * Shading
+ * Shading.
*
- * @var \PhpOffice\PhpWord\Style\Shading
+ * @var Shading
*/
private $shading;
/**
- * Right to left languages
+ * Right to left languages.
*
- * @var bool
+ * @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 +247,49 @@ class Font extends AbstractStyle
private $noProof;
/**
- * Languages
+ * Languages.
*
- * @var \PhpOffice\PhpWord\Style\Language
+ * @var null|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
+ * Preservation of white space in html.
+ *
+ * @var string Value used for css white-space
+ */
+ private $whiteSpace = '';
+
+ /**
+ * Generic font as fallback for html.
+ *
+ * @var string generic font name
+ */
+ private $fallbackFont = '';
+
+ /**
+ * Create new font style.
*
* @param string $type Type of font
- * @param array|string|\PhpOffice\PhpWord\Style\AbstractStyle $paragraph Paragraph styles definition
+ * @param AbstractStyle|array|string $paragraph Paragraph styles definition
*/
public function __construct($type = 'text', $paragraph = null)
{
@@ -281,51 +298,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(),
+ return [
+ '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(),
- );
-
- return $styles;
- }
-
- /**
- * Get style type
+ '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(),
+ 'whiteSpace' => $this->getWhiteSpace(),
+ 'fallbackFont' => $this->getFallbackFont(),
+ ];
+ }
+
+ /**
+ * Get style type.
*
* @return string
*/
@@ -335,7 +353,7 @@ public function getStyleType()
}
/**
- * Get font name
+ * Get font name.
*
* @return string
*/
@@ -345,9 +363,10 @@ public function getName()
}
/**
- * Set font name
+ * Set font name.
*
* @param string $value
+ *
* @return self
*/
public function setName($value = null)
@@ -358,7 +377,7 @@ public function setName($value = null)
}
/**
- * Get Font Content Type
+ * Get Font Content Type.
*
* @return string
*/
@@ -368,9 +387,10 @@ public function getHint()
}
/**
- * Set Font Content Type
+ * Set Font Content Type.
*
* @param string $value
+ *
* @return self
*/
public function setHint($value = null)
@@ -381,9 +401,9 @@ public function setHint($value = null)
}
/**
- * Get font size
+ * Get font size.
*
- * @return int|float
+ * @return float|int
*/
public function getSize()
{
@@ -391,9 +411,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,19 +425,18 @@ public function setSize($value = null)
}
/**
- * Get font color
- *
- * @return string
+ * Get font color.
*/
- public function getColor()
+ public function getColor(): ?string
{
return $this->color;
}
/**
- * Set font color
+ * Set font color.
*
* @param string $value
+ *
* @return self
*/
public function setColor($value = null)
@@ -427,7 +447,7 @@ public function setColor($value = null)
}
/**
- * Get bold
+ * Get bold.
*
* @return bool
*/
@@ -437,9 +457,10 @@ public function isBold()
}
/**
- * Set bold
+ * Set bold.
*
* @param bool $value
+ *
* @return self
*/
public function setBold($value = true)
@@ -450,7 +471,7 @@ public function setBold($value = true)
}
/**
- * Get italic
+ * Get italic.
*
* @return bool
*/
@@ -460,9 +481,10 @@ public function isItalic()
}
/**
- * Set italic
+ * Set italic.
*
* @param bool $value
+ *
* @return self
*/
public function setItalic($value = true)
@@ -473,7 +495,7 @@ public function setItalic($value = true)
}
/**
- * Get underline
+ * Get underline.
*
* @return string
*/
@@ -483,9 +505,10 @@ public function getUnderline()
}
/**
- * Set underline
+ * Set underline.
*
* @param string $value
+ *
* @return self
*/
public function setUnderline($value = self::UNDERLINE_NONE)
@@ -496,7 +519,7 @@ public function setUnderline($value = self::UNDERLINE_NONE)
}
/**
- * Get superscript
+ * Get superscript.
*
* @return bool
*/
@@ -506,9 +529,10 @@ public function isSuperScript()
}
/**
- * Set superscript
+ * Set superscript.
*
* @param bool $value
+ *
* @return self
*/
public function setSuperScript($value = true)
@@ -517,7 +541,7 @@ public function setSuperScript($value = true)
}
/**
- * Get subscript
+ * Get subscript.
*
* @return bool
*/
@@ -527,9 +551,10 @@ public function isSubScript()
}
/**
- * Set subscript
+ * Set subscript.
*
* @param bool $value
+ *
* @return self
*/
public function setSubScript($value = true)
@@ -538,49 +563,43 @@ public function setSubScript($value = true)
}
/**
- * Get strikethrough
- *
- * @return bool
+ * Get strikethrough.
*/
- public function isStrikethrough()
+ public function isStrikethrough(): ?bool
{
return $this->strikethrough;
}
/**
- * Set strikethrough
+ * 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
+ * Get double strikethrough.
*/
- public function isDoubleStrikethrough()
+ public function isDoubleStrikethrough(): ?bool
{
return $this->doubleStrikethrough;
}
/**
- * Set double strikethrough
+ * 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);
}
/**
- * 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
+ *
+ * @return 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,22 +795,23 @@ 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
+ * @return Paragraph
*/
public function getParagraph()
{
@@ -791,9 +819,10 @@ public function getParagraph()
}
/**
- * Set Paragraph
+ * Set Paragraph.
*
* @param mixed $value
+ *
* @return self
*/
public function setParagraph($value = null)
@@ -804,19 +833,20 @@ public function setParagraph($value = null)
}
/**
- * Get rtl
+ * Get rtl.
*
- * @return bool
+ * @return ?bool
*/
public function isRTL()
{
- return $this->rtl;
+ return $this->rtl ?? Settings::isDefaultRtl();
}
/**
- * Set rtl
+ * Set rtl.
+ *
+ * @param ?bool $value
*
- * @param bool $value
* @return self
*/
public function setRTL($value = true)
@@ -827,9 +857,9 @@ public function setRTL($value = true)
}
/**
- * Get shading
+ * Get shading.
*
- * @return \PhpOffice\PhpWord\Style\Shading
+ * @return Shading
*/
public function getShading()
{
@@ -837,9 +867,10 @@ public function getShading()
}
/**
- * Set shading
+ * Set shading.
*
* @param mixed $value
+ *
* @return self
*/
public function setShading($value = null)
@@ -850,9 +881,9 @@ public function setShading($value = null)
}
/**
- * Get language
+ * Get language.
*
- * @return \PhpOffice\PhpWord\Style\Language
+ * @return null|Language
*/
public function getLang()
{
@@ -860,9 +891,10 @@ public function getLang()
}
/**
- * Set language
+ * Set language.
*
* @param mixed $value
+ *
* @return self
*/
public function setLang($value = null)
@@ -876,120 +908,90 @@ public function setLang($value = null)
}
/**
- * Get bold
+ * Get hidden text.
*
- * @deprecated 0.10.0
- *
- * @codeCoverageIgnore
+ * @return bool
*/
- public function getBold()
+ public function isHidden()
{
- return $this->isBold();
+ return $this->hidden;
}
/**
- * Get italic
+ * Set hidden text.
*
- * @deprecated 0.10.0
+ * @param bool $value
*
- * @codeCoverageIgnore
+ * @return self
*/
- public function getItalic()
+ public function setHidden($value = true)
{
- return $this->isItalic();
- }
+ $this->hidden = $this->setBoolVal($value, $this->hidden);
- /**
- * Get superscript
- *
- * @deprecated 0.10.0
- *
- * @codeCoverageIgnore
- */
- public function getSuperScript()
- {
- return $this->isSuperScript();
+ return $this;
}
/**
- * Get subscript
- *
- * @deprecated 0.10.0
+ * Get position.
*
- * @codeCoverageIgnore
+ * @return int
*/
- public function getSubScript()
+ public function getPosition()
{
- return $this->isSubScript();
+ return $this->position;
}
/**
- * Get strikethrough
+ * Set position.
*
- * @deprecated 0.10.0
+ * @param int $value
*
- * @codeCoverageIgnore
+ * @return self
*/
- public function getStrikethrough()
+ public function setPosition($value = null)
{
- return $this->isStrikethrough();
+ $this->position = $this->setIntVal($value, null);
+
+ return $this;
}
/**
- * Get paragraph style
- *
- * @deprecated 0.11.0
+ * Set html css white-space value. It is expected that only pre-wrap and normal (default) are useful.
*
- * @codeCoverageIgnore
+ * @param null|string $value Should be one of pre-wrap, normal, nowrap, pre, pre-line, initial, inherit
*/
- public function getParagraphStyle()
+ public function setWhiteSpace(?string $value): self
{
- return $this->getParagraph();
+ $this->whiteSpace = Validate::validateCSSWhiteSpace($value);
+
+ return $this;
}
/**
- * Get hidden text
- *
- * @return bool
+ * Get html css white-space value.
*/
- public function isHidden()
+ public function getWhiteSpace(): string
{
- return $this->hidden;
+ return $this->whiteSpace;
}
/**
- * Set hidden text
+ * Set generic font for fallback for html.
*
- * @param bool $value
- * @return self
+ * @param string $value generic font name
*/
- public function setHidden($value = true)
+ public function setFallbackFont(?string $value): self
{
- $this->hidden = $this->setBoolVal($value, $this->hidden);
+ $this->fallbackFont = Validate::validateCSSGenericFont($value);
return $this;
}
/**
- * Get position
- *
- * @return int
- */
- public function getPosition()
- {
- return $this->position;
- }
-
- /**
- * Set position
- *
- * @param int $value
- * @return self
+ * Get html fallback generic font.
*/
- public function setPosition($value = null)
+ public function getFallbackFont(): string
{
- $this->position = $this->setIntVal($value, null);
-
- return $this;
+ return $this->fallbackFont;
}
}
diff --git a/src/PhpWord/Style/Frame.php b/src/PhpWord/Style/Frame.php
index e87b7a803a..016722f36c 100644
--- a/src/PhpWord/Style/Frame.php
+++ b/src/PhpWord/Style/Frame.php
@@ -1,4 +1,5 @@
setStyleByArray($style);
}
@@ -244,33 +247,7 @@ public function setAlignment($value)
}
/**
- * @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
+ * Get unit.
*
* @return string
*/
@@ -280,9 +257,10 @@ public function getUnit()
}
/**
- * Set unit
+ * Set unit.
*
* @param string $value
+ *
* @return self
*/
public function setUnit($value)
@@ -293,9 +271,9 @@ public function setUnit($value)
}
/**
- * Get width
+ * Get width.
*
- * @return int|float
+ * @return float|int
*/
public function getWidth()
{
@@ -303,9 +281,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 +295,9 @@ public function setWidth($value = null)
}
/**
- * Get height
+ * Get height.
*
- * @return int|float
+ * @return float|int
*/
public function getHeight()
{
@@ -326,9 +305,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 +319,9 @@ public function setHeight($value = null)
}
/**
- * Get left
+ * Get left.
*
- * @return int|float
+ * @return float|int
*/
public function getLeft()
{
@@ -349,9 +329,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 +343,9 @@ public function setLeft($value = 0)
}
/**
- * Get topmost position
+ * Get topmost position.
*
- * @return int|float
+ * @return float|int
*/
public function getTop()
{
@@ -372,9 +353,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 +367,7 @@ public function setTop($value = 0)
}
/**
- * Get position type
+ * Get position type.
*
* @return string
*/
@@ -395,24 +377,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 +405,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 +439,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 +473,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 +490,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 +507,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 +524,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 +541,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 +557,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 +574,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 +588,7 @@ public function setWrapDistanceTop($value = null)
}
/**
- * Get bottom distance from text wrap
+ * Get bottom distance from text wrap.
*
* @return float
*/
@@ -609,9 +598,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 +612,7 @@ public function setWrapDistanceBottom($value = null)
}
/**
- * Get left distance from text wrap
+ * Get left distance from text wrap.
*
* @return float
*/
@@ -632,9 +622,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 +636,7 @@ public function setWrapDistanceLeft($value = null)
}
/**
- * Get right distance from text wrap
+ * Get right distance from text wrap.
*
* @return float
*/
@@ -655,9 +646,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 +660,7 @@ public function setWrapDistanceRight($value = null)
}
/**
- * Get position
+ * Get position.
*
* @return int
*/
@@ -678,9 +670,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..f53a778793 100644
--- a/src/PhpWord/Style/Image.php
+++ b/src/PhpWord/Style/Image.php
@@ -1,4 +1,5 @@
setStyleByArray($style);
}
/**
- * Get left
- *
- * @return int|float
+ * Get left.
*/
- public function getLeft()
+ public function getLeft(): ?float
{
return $this->left;
}
/**
- * Set left
- *
- * @param int|float $value
- * @return self
+ * Set left.
*/
- public function setLeft($value = null)
+ public function setLeft(?float $value): self
{
- $this->left = $this->setNumericVal($value, $this->left);
+ $this->left = $this->setNumericVal($value);
return $this;
}
/**
- * Get right
- *
- * @return int|float
+ * Get right.
*/
- public function getRight()
+ public function getRight(): ?float
{
return $this->right;
}
/**
- * Set right
- *
- * @param int|float $value
- * @return self
+ * Set right.
*/
- public function setRight($value = null)
+ public function setRight(?float $value): self
{
- $this->right = $this->setNumericVal($value, $this->right);
+ $this->right = $this->setNumericVal($value);
return $this;
}
/**
- * Get first line
- *
- * @return int|float
+ * Get first line.
*/
- public function getFirstLine()
+ public function getFirstLine(): ?float
{
return $this->firstLine;
}
/**
- * Set first line
- *
- * @param int|float $value
- * @return self
+ * Set first line.
*/
- public function setFirstLine($value = null)
+ public function setFirstLine(?float $value): self
{
- $this->firstLine = $this->setNumericVal($value, $this->firstLine);
+ $this->firstLine = $this->setNumericVal($value);
return $this;
}
/**
- * Get hanging
- *
- * @return int|float
+ * Get first line chars.
*/
- public function getHanging()
+ 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.
+ */
+ public function getHanging(): ?float
{
return $this->hanging;
}
/**
- * Set hanging
- *
- * @param int|float $value
- * @return self
+ * Set hanging.
*/
- 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/Language.php b/src/PhpWord/Style/Language.php
index 18ef88975f..641ed7b41e 100644
--- a/src/PhpWord/Style/Language.php
+++ b/src/PhpWord/Style/Language.php
@@ -1,4 +1,5 @@
setLatin($latin);
@@ -124,13 +136,12 @@ 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)
+ public function setLatin(?string $latin): self
{
$this->latin = $this->validateLocale($latin);
@@ -138,21 +149,21 @@ public function setLatin($latin)
}
/**
- * Get the Latin Language
- *
- * @return string|null
+ * Get the Latin Language.
*/
- public function getLatin()
+ public function getLatin(): ?string
{
return $this->latin;
}
/**
- * 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 +174,7 @@ public function setLangId($langId)
}
/**
- * Get the Language ID
+ * Get the Language ID.
*
* @return int
*/
@@ -173,10 +184,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 +199,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 +209,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 +224,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,19 +234,26 @@ 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)
{
- if (strlen($locale) === 2) {
- return strtolower($locale) . '-' . strtoupper($locale);
+ if ($locale !== null) {
+ $locale = str_replace('_', '-', $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');
+ 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..cc5a12ffe9 100644
--- a/src/PhpWord/Style/Line.php
+++ b/src/PhpWord/Style/Line.php
@@ -1,4 +1,5 @@
connectorType = $this->setEnumVal($value, $enum, $this->connectorType);
return $this;
}
/**
- * Get weight
+ * Get weight.
*
* @return int
*/
@@ -162,9 +165,10 @@ public function getWeight()
}
/**
- * Set weight
+ * Set weight.
*
* @param int $value Weight in points
+ *
* @return self
*/
public function setWeight($value = null)
@@ -175,7 +179,7 @@ public function setWeight($value = null)
}
/**
- * Get color
+ * Get color.
*
* @return string
*/
@@ -185,9 +189,10 @@ public function getColor()
}
/**
- * Set color
+ * Set color.
*
* @param string $value
+ *
* @return self
*/
public function setColor($value = null)
@@ -198,7 +203,7 @@ public function setColor($value = null)
}
/**
- * Get beginArrow
+ * Get beginArrow.
*
* @return string
*/
@@ -208,24 +213,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 +241,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 +269,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..95267a295e 100644
--- a/src/PhpWord/Style/LineNumbering.php
+++ b/src/PhpWord/Style/LineNumbering.php
@@ -1,4 +1,5 @@
setStyleByArray($style);
}
/**
- * Get start
+ * Get start.
*
* @return int
*/
@@ -80,9 +82,10 @@ public function getStart()
}
/**
- * Set start
+ * Set start.
*
* @param int $value
+ *
* @return self
*/
public function setStart($value = null)
@@ -93,7 +96,7 @@ public function setStart($value = null)
}
/**
- * Get increment
+ * Get increment.
*
* @return int
*/
@@ -103,9 +106,10 @@ public function getIncrement()
}
/**
- * Set increment
+ * Set increment.
*
* @param int $value
+ *
* @return self
*/
public function setIncrement($value = null)
@@ -116,9 +120,9 @@ public function setIncrement($value = null)
}
/**
- * Get distance
+ * Get distance.
*
- * @return int|float
+ * @return float|int
*/
public function getDistance()
{
@@ -126,9 +130,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 +144,7 @@ public function setDistance($value = null)
}
/**
- * Get restart
+ * Get restart.
*
* @return string
*/
@@ -149,14 +154,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 306ecff305..e34aeb7c7c 100644
--- a/src/PhpWord/Style/ListItem.php
+++ b/src/PhpWord/Style/ListItem.php
@@ -1,4 +1,5 @@
listType = $this->setEnumVal($value, $enum, $this->listType);
$this->getListTypeStyle();
@@ -102,7 +106,7 @@ public function setListType($value = self::TYPE_BULLET_FILLED)
}
/**
- * Get numbering style name
+ * Get numbering style name.
*
* @return string
*/
@@ -112,9 +116,10 @@ public function getNumStyle()
}
/**
- * Set numbering style name
+ * Set numbering style name.
*
* @param string $value
+ *
* @return self
*/
public function setNumStyle($value)
@@ -130,7 +135,7 @@ public function setNumStyle($value)
}
/**
- * Get numbering Id
+ * Get numbering Id.
*
* @return int
*/
@@ -140,15 +145,32 @@ public function getNumId()
}
/**
- * Get legacy numbering definition
+ * Set numbering Id. Same numId means same list.
+ *
+ * @param mixed $numInt
+ */
+ public function setNumId($numInt): void
+ {
+ $this->numId = $numInt;
+ $this->getListTypeStyle();
+ }
+
+ /**
+ * Get legacy numbering definition.
*
* @return array
+ *
* @since 0.10.0
*/
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 .= 'NumId' . $this->numId;
+ }
+
if (Style::getStyle($numStyle) !== null) {
$this->setNumStyle($numStyle);
@@ -156,13 +178,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',
@@ -172,11 +194,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',
@@ -186,11 +208,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',
@@ -200,11 +222,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',
@@ -214,11 +236,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, , ',
@@ -228,11 +250,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, , ',
@@ -242,18 +264,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..2b34f2a9bb 100644
--- a/src/PhpWord/Style/Numbering.php
+++ b/src/PhpWord/Style/Numbering.php
@@ -1,4 +1,5 @@
numId;
}
/**
- * Set Id
- *
- * @param int $value
- * @return self
+ * Set Id.
*/
- public function setNumId($value)
+ public function setNumId(int $value): self
{
$this->numId = $this->setIntVal($value, $this->numId);
@@ -74,56 +72,46 @@ public function setNumId($value)
}
/**
- * Get multilevel type
- *
- * @return string
+ * Get multilevel type.
*/
- public function getType()
+ public function getType(): ?string
{
return $this->type;
}
/**
- * Set multilevel type
- *
- * @param string $value
- * @return self
+ * Set multilevel type.
*/
- public function setType($value)
+ public function setType(string $value): self
{
- $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[]
*/
- public function getLevels()
+ public function getLevels(): array
{
return $this->levels;
}
/**
- * Set multilevel type
- *
- * @param array $values
- * @return self
+ * Set multilevel type.
*/
- public function setLevels($values)
+ 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 e9b32f0135..f2505a330d 100644
--- a/src/PhpWord/Style/NumberingLevel.php
+++ b/src/PhpWord/Style/NumberingLevel.php
@@ -1,4 +1,5 @@
suffix = $this->setEnumVal($value, $enum, $this->suffix);
return $this;
}
/**
- * Get text
+ * Get text.
*
* @return string
*/
@@ -276,9 +290,10 @@ public function getText()
}
/**
- * Set text
+ * Set text.
*
* @param string $value
+ *
* @return self
*/
public function setText($value)
@@ -315,33 +330,7 @@ public function setAlignment($value)
}
/**
- * @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)
- {
- return $this->setAlignment($value);
- }
-
- /**
- * Get left
+ * Get left.
*
* @return int
*/
@@ -351,9 +340,10 @@ public function getLeft()
}
/**
- * Set left
+ * Set left.
*
* @param int $value
+ *
* @return self
*/
public function setLeft($value)
@@ -364,7 +354,7 @@ public function setLeft($value)
}
/**
- * Get hanging
+ * Get hanging.
*
* @return int
*/
@@ -374,9 +364,10 @@ public function getHanging()
}
/**
- * Set hanging
+ * Set hanging.
*
* @param int $value
+ *
* @return self
*/
public function setHanging($value)
@@ -387,7 +378,7 @@ public function setHanging($value)
}
/**
- * Get tab
+ * Get tab.
*
* @return int
*/
@@ -397,9 +388,10 @@ public function getTabPos()
}
/**
- * Set tab
+ * Set tab.
*
* @param int $value
+ *
* @return self
*/
public function setTabPos($value)
@@ -410,7 +402,7 @@ public function setTabPos($value)
}
/**
- * Get font
+ * Get font.
*
* @return string
*/
@@ -420,9 +412,10 @@ public function getFont()
}
/**
- * Set font
+ * Set font.
*
* @param string $value
+ *
* @return self
*/
public function setFont($value)
@@ -433,7 +426,7 @@ public function setFont($value)
}
/**
- * Get hint
+ * Get hint.
*
* @return string
*/
@@ -443,14 +436,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..7706580825 100644
--- a/src/PhpWord/Style/Outline.php
+++ b/src/PhpWord/Style/Outline.php
@@ -1,4 +1,5 @@
setStyleByArray($style);
}
/**
- * Get unit
+ * Get unit.
*
* @return string
*/
@@ -139,9 +144,9 @@ public function getUnit()
}
/**
- * Get weight
+ * Get weight.
*
- * @return int|float
+ * @return float|int
*/
public function getWeight()
{
@@ -149,9 +154,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 +168,7 @@ public function setWeight($value = null)
}
/**
- * Get color
+ * Get color.
*
* @return string
*/
@@ -172,9 +178,10 @@ public function getColor()
}
/**
- * Set color
+ * Set color.
*
* @param string $value
+ *
* @return self
*/
public function setColor($value = null)
@@ -185,7 +192,7 @@ public function setColor($value = null)
}
/**
- * Get dash type
+ * Get dash type.
*
* @return string
*/
@@ -195,9 +202,10 @@ public function getDash()
}
/**
- * Set dash type
+ * Set dash type.
*
* @param string $value
+ *
* @return self
*/
public function setDash($value = null)
@@ -208,7 +216,7 @@ public function setDash($value = null)
}
/**
- * Get line style
+ * Get line style.
*
* @return string
*/
@@ -218,22 +226,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 +252,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 +277,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 +303,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..c59ea42d7b 100644
--- a/src/PhpWord/Style/Paper.php
+++ b/src/PhpWord/Style/Paper.php
@@ -1,4 +1,5 @@
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 +141,7 @@ public function __construct($size = 'A4')
}
/**
- * Get size
+ * Get size.
*
* @return string
*/
@@ -150,16 +151,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 +175,7 @@ public function setSize($size)
}
/**
- * Get width
+ * Get width.
*
* @return float
*/
@@ -183,7 +185,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 6e9aaf15dc..5ab7ade673 100644
--- a/src/PhpWord/Style/Paragraph.php
+++ b/src/PhpWord/Style/Paragraph.php
@@ -1,4 +1,5 @@
'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,163 +85,165 @@ class Paragraph extends Border
private $alignment = '';
/**
- * Indentation
+ * Indentation.
*
- * @var \PhpOffice\PhpWord\Style\Indentation
+ * @var null|Indentation
*/
private $indentation;
/**
- * Spacing
+ * Spacing.
*
- * @var \PhpOffice\PhpWord\Style\Spacing
+ * @var Spacing
*/
private $spacing;
/**
- * Text line height
+ * Text line height.
*
- * @var int
+ * @var null|float|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[]
+ * @var Tab[]
*/
- private $tabs = array();
+ private $tabs = [];
/**
- * Shading
+ * Shading.
*
- * @var \PhpOffice\PhpWord\Style\Shading
+ * @var 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
+ * @var ?bool
*/
- private $bidi = false;
+ private $bidi;
/**
- * 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)
{
$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);
}
/**
- * 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;
}
@@ -271,146 +275,192 @@ public function setAlignment($value)
}
/**
- * @deprecated 0.13.0 Use the `getAlignment` method instead.
+ * Get parent style ID.
*
* @return string
- *
- * @codeCoverageIgnore
*/
- public function getAlign()
+ public function getBasedOn()
{
- return $this->getAlignment();
+ return $this->basedOn;
}
/**
- * @deprecated 0.13.0 Use the `setAlignment` method instead.
+ * Set parent style ID.
*
* @param string $value
*
* @return self
- *
- * @codeCoverageIgnore
*/
- public function setAlign($value = null)
+ public function setBasedOn($value = 'Normal')
{
- return $this->setAlignment($value);
+ $this->basedOn = $value;
+
+ return $this;
}
/**
- * Get parent style ID
+ * Get style for next paragraph.
*
* @return string
*/
- public function getBasedOn()
+ public function getNext()
{
- return $this->basedOn;
+ return $this->next;
}
/**
- * Set parent style ID
+ * Set style for next paragraph.
*
* @param string $value
+ *
* @return self
*/
- public function setBasedOn($value = 'Normal')
+ public function setNext($value = null)
{
- $this->basedOn = $value;
+ $this->next = $value;
return $this;
}
/**
- * Get style for next paragraph
- *
- * @return string
+ * Get hanging.
*/
- public function getNext()
+ public function getHanging(): ?float
{
- return $this->next;
+ return $this->getChildStyleValue($this->indentation, 'hanging');
}
/**
- * Set style for next paragraph
+ * Get indentation.
*
- * @param string $value
- * @return self
+ * @deprecated 1.4.0 Use getIndentLeft
*/
- public function setNext($value = null)
+ public function getIndent(): ?float
{
- $this->next = $value;
+ return $this->getChildStyleValue($this->indentation, 'left');
+ }
- return $this;
+ /**
+ * Get indentation.
+ */
+ public function getIndentation(): ?Indentation
+ {
+ return $this->indentation;
}
/**
- * Get shading
+ * Get firstLine.
+ */
+ public function getIndentFirstLine(): ?float
+ {
+ return $this->getChildStyleValue($this->indentation, 'firstLine');
+ }
+
+ /**
+ * Get left indentation.
+ */
+ public function getIndentLeft(): ?float
+ {
+ return $this->getChildStyleValue($this->indentation, 'left');
+ }
+
+ /**
+ * Get right indentation.
+ */
+ public function getIndentRight(): ?float
+ {
+ return $this->getChildStyleValue($this->indentation, 'right');
+ }
+
+ /**
+ * Set hanging.
*
- * @return \PhpOffice\PhpWord\Style\Indentation
+ * @deprecated 1.4.0 Use setIndentHanging
*/
- public function getIndentation()
+ public function setHanging(?float $value = null): self
{
- return $this->indentation;
+ return $this->setIndentation(['hanging' => $value]);
}
/**
- * Set shading
+ * Set indentation.
*
- * @param mixed $value
- * @return self
+ * @deprecated 1.4.0 Use setIndentLeft
+ */
+ public function setIndent(?float $value = null): self
+ {
+ return $this->setIndentation(['left' => $value]);
+ }
+
+ /**
+ * Set indentation.
+ *
+ * @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 setIndentation($value = null)
+ public function setIndentation(array $value = []): self
{
+ $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;
}
/**
- * Get indentation
- *
- * @return int
+ * Set hanging indentation.
*/
- public function getIndent()
+ public function setIndentHanging(?float $value = null): self
{
- return $this->getChildStyleValue($this->indentation, 'left');
+ return $this->setIndentation(['hanging' => $value]);
}
/**
- * Set indentation
- *
- * @param int $value
- * @return self
+ * Set firstline indentation.
*/
- public function setIndent($value = null)
+ public function setIndentFirstLine(?float $value = null): self
{
- return $this->setIndentation(array('left' => $value));
+ return $this->setIndentation(['firstLine' => $value]);
}
/**
- * Get hanging
- *
- * @return int
+ * Set firstlineChars indentation.
*/
- public function getHanging()
+ public function setIndentFirstLineChars(int $value = 0): self
{
- return $this->getChildStyleValue($this->indentation, 'hanging');
+ return $this->setIndentation(['firstLineChars' => $value]);
}
/**
- * Set hanging
- *
- * @param int $value
- * @return self
+ * Set left indentation.
+ */
+ public function setIndentLeft(?float $value = null): self
+ {
+ return $this->setIndentation(['left' => $value]);
+ }
+
+ /**
+ * Set right indentation.
*/
- public function setHanging($value = null)
+ public function setIndentRight(?float $value = null): self
{
- return $this->setIndentation(array('hanging' => $value));
+ return $this->setIndentation(['right' => $value]);
}
/**
- * Get spacing
+ * Get spacing.
+ *
+ * @return Spacing
*
- * @return \PhpOffice\PhpWord\Style\Spacing
* @todo Rename to getSpacing in 1.0
*/
public function getSpace()
@@ -419,10 +469,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,9 +485,9 @@ public function setSpace($value = null)
}
/**
- * Get space before paragraph
+ * Get space before paragraph.
*
- * @return int
+ * @return null|float|int
*/
public function getSpaceBefore()
{
@@ -443,20 +495,21 @@ public function getSpaceBefore()
}
/**
- * Set space before paragraph
+ * Set space before paragraph.
+ *
+ * @param null|float|int $value
*
- * @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
+ * @return null|float|int
*/
public function getSpaceAfter()
{
@@ -464,20 +517,21 @@ public function getSpaceAfter()
}
/**
- * Set space after paragraph
+ * Set space after paragraph.
+ *
+ * @param null|float|int $value
*
- * @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 null|float|int
*/
public function getSpacing()
{
@@ -485,18 +539,19 @@ public function getSpacing()
}
/**
- * Set spacing between lines
+ * Set spacing between lines.
+ *
+ * @param null|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 +561,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
+ *
+ * @return 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 null|float|int
*/
public function getLineHeight()
{
@@ -527,11 +583,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 +607,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 +617,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 +631,7 @@ public function setWidowControl($value = true)
}
/**
- * Get keep paragraph with next paragraph setting
+ * Get keep paragraph with next paragraph setting.
*
* @return bool
*/
@@ -585,9 +641,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 +655,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 +665,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 +679,7 @@ public function setKeepLines($value = true)
}
/**
- * Get start paragraph on next page setting
+ * Get start paragraph on next page setting.
*
* @return bool
*/
@@ -631,9 +689,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 +703,7 @@ public function setPageBreakBefore($value = true)
}
/**
- * Get numbering style name
+ * Get numbering style name.
*
* @return string
*/
@@ -654,9 +713,10 @@ public function getNumStyle()
}
/**
- * Set numbering style name
+ * Set numbering style name.
*
* @param string $value
+ *
* @return self
*/
public function setNumStyle($value)
@@ -667,7 +727,7 @@ public function setNumStyle($value)
}
/**
- * Get numbering level
+ * Get numbering level.
*
* @return int
*/
@@ -677,9 +737,10 @@ public function getNumLevel()
}
/**
- * Set numbering level
+ * Set numbering level.
*
* @param int $value
+ *
* @return self
*/
public function setNumLevel($value = 0)
@@ -690,9 +751,9 @@ public function setNumLevel($value = 0)
}
/**
- * Get tabs
+ * Get tabs.
*
- * @return \PhpOffice\PhpWord\Style\Tab[]
+ * @return Tab[]
*/
public function getTabs()
{
@@ -700,9 +761,10 @@ public function getTabs()
}
/**
- * Set tabs
+ * Set tabs.
*
* @param array $value
+ *
* @return self
*/
public function setTabs($value = null)
@@ -715,57 +777,9 @@ public function setTabs($value = null)
}
/**
- * Get allow first/last line to display on a separate page setting
+ * Get shading.
*
- * @deprecated 0.10.0
- *
- * @codeCoverageIgnore
- */
- public function getWidowControl()
- {
- return $this->hasWidowControl();
- }
-
- /**
- * Get keep paragraph with next paragraph setting
- *
- * @deprecated 0.10.0
- *
- * @codeCoverageIgnore
- */
- public function getKeepNext()
- {
- return $this->isKeepNext();
- }
-
- /**
- * Get keep all lines on one page setting
- *
- * @deprecated 0.10.0
- *
- * @codeCoverageIgnore
- */
- public function getKeepLines()
- {
- return $this->isKeepLines();
- }
-
- /**
- * Get start paragraph on next page setting
- *
- * @deprecated 0.10.0
- *
- * @codeCoverageIgnore
- */
- public function getPageBreakBefore()
- {
- return $this->hasPageBreakBefore();
- }
-
- /**
- * Get shading
- *
- * @return \PhpOffice\PhpWord\Style\Shading
+ * @return Shading
*/
public function getShading()
{
@@ -773,9 +787,10 @@ public function getShading()
}
/**
- * Set shading
+ * Set shading.
*
* @param mixed $value
+ *
* @return self
*/
public function setShading($value = null)
@@ -786,7 +801,7 @@ public function setShading($value = null)
}
/**
- * Get contextualSpacing
+ * Get contextualSpacing.
*
* @return bool
*/
@@ -796,9 +811,10 @@ public function hasContextualSpacing()
}
/**
- * Set contextualSpacing
+ * Set contextualSpacing.
*
* @param bool $contextualSpacing
+ *
* @return self
*/
public function setContextualSpacing($contextualSpacing)
@@ -809,20 +825,21 @@ public function setContextualSpacing($contextualSpacing)
}
/**
- * Get bidirectional
+ * Get bidirectional.
*
- * @return bool
+ * @return ?bool
*/
public function isBidi()
{
- return $this->bidi;
+ return $this->bidi ?? Settings::isDefaultRtl();
}
/**
- * Set bidi
+ * Set bidi.
*
- * @param bool $bidi
+ * @param ?bool $bidi
* Set to true to write from right to left
+ *
* @return self
*/
public function setBidi($bidi)
@@ -833,7 +850,7 @@ public function setBidi($bidi)
}
/**
- * Get textAlignment
+ * Get textAlignment.
*
* @return string
*/
@@ -843,9 +860,10 @@ public function getTextAlignment()
}
/**
- * Set textAlignment
+ * Set textAlignment.
*
* @param string $textAlignment
+ *
* @return self
*/
public function setTextAlignment($textAlignment)
@@ -867,7 +885,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..749839c4e2 100644
--- a/src/PhpWord/Style/Row.php
+++ b/src/PhpWord/Style/Row.php
@@ -1,4 +1,5 @@
tblHeader;
}
/**
- * Is tblHeader
- *
- * @param bool $value
- * @return self
+ * Is tblHeader.
*/
- public function setTblHeader($value = true)
+ public function setTblHeader(bool $value = true): self
{
$this->tblHeader = $this->setBoolVal($value, $this->tblHeader);
@@ -76,22 +72,17 @@ public function setTblHeader($value = true)
}
/**
- * Is cantSplit
- *
- * @return bool
+ * Is cantSplit.
*/
- public function isCantSplit()
+ public function isCantSplit(): bool
{
return $this->cantSplit;
}
/**
- * Is cantSplit
- *
- * @param bool $value
- * @return self
+ * Is cantSplit.
*/
- public function setCantSplit($value = true)
+ public function setCantSplit(bool $value = true): self
{
$this->cantSplit = $this->setBoolVal($value, $this->cantSplit);
@@ -99,61 +90,20 @@ public function setCantSplit($value = true)
}
/**
- * Is exactHeight
- *
- * @return bool
+ * Is exactHeight.
*/
- public function isExactHeight()
+ public function isExactHeight(): bool
{
return $this->exactHeight;
}
/**
- * Set exactHeight
- *
- * @param bool $value
- * @return self
+ * Set exactHeight.
*/
- public function setExactHeight($value = true)
+ public function setExactHeight(bool $value = true): self
{
$this->exactHeight = $this->setBoolVal($value, $this->exactHeight);
return $this;
}
-
- /**
- * Get tblHeader
- *
- * @deprecated 0.10.0
- *
- * @codeCoverageIgnore
- */
- public function getTblHeader()
- {
- return $this->isTblHeader();
- }
-
- /**
- * Get cantSplit
- *
- * @deprecated 0.10.0
- *
- * @codeCoverageIgnore
- */
- public function getCantSplit()
- {
- return $this->isCantSplit();
- }
-
- /**
- * Get exactHeight
- *
- * @deprecated 0.10.0
- *
- * @codeCoverageIgnore
- */
- public function getExactHeight()
- {
- return $this->isExactHeight();
- }
}
diff --git a/src/PhpWord/Style/Section.php b/src/PhpWord/Style/Section.php
index ff9b0be09a..1f8e1f5c41 100644
--- a/src/PhpWord/Style/Section.php
+++ b/src/PhpWord/Style/Section.php
@@ -1,4 +1,5 @@
paper === null) {
$this->paper = new Paper();
}
@@ -213,10 +193,11 @@ public function setPaperSize($value = 'A4')
}
/**
- * Set Setting Value
+ * Set Setting Value.
*
* @param string $key
- * @param string $value
+ * @param array|int|string $value
+ *
* @return self
*/
public function setSettingValue($key, $value)
@@ -225,20 +206,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) {
@@ -253,7 +235,7 @@ public function setOrientation($value = null)
}
/**
- * Get Page Orientation
+ * Get Page Orientation.
*
* @return string
*/
@@ -263,7 +245,7 @@ public function getOrientation()
}
/**
- * Set Portrait Orientation
+ * Set Portrait Orientation.
*
* @return self
*/
@@ -273,7 +255,7 @@ public function setPortrait()
}
/**
- * Set Landscape Orientation
+ * Set Landscape Orientation.
*
* @return self
*/
@@ -283,9 +265,9 @@ public function setLandscape()
}
/**
- * Get Page Size Width
+ * Get Page Size Width.
*
- * @return int|float|null
+ * @return null|float|int
*
* @since 0.12.0
*/
@@ -295,9 +277,9 @@ public function getPageSizeW()
}
/**
- * @param int|float|null $value
+ * @param null|float|int $value
*
- * @return \PhpOffice\PhpWord\Style\Section
+ * @return Section
*
* @since 0.12.0
*/
@@ -309,9 +291,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
*/
@@ -321,9 +303,9 @@ public function getPageSizeH()
}
/**
- * @param int|float|null $value
+ * @param null|float|int $value
*
- * @return \PhpOffice\PhpWord\Style\Section
+ * @return Section
*
* @since 0.12.0
*/
@@ -335,101 +317,9 @@ public function setPageSizeH($value = null)
}
/**
- * Get Margin Top
- *
- * @return int|float
- */
- public function getMarginTop()
- {
- return $this->marginTop;
- }
-
- /**
- * Set Margin Top
- *
- * @param int|float $value
- * @return self
- */
- public function setMarginTop($value = null)
- {
- $this->marginTop = $this->setNumericVal($value, self::DEFAULT_MARGIN);
-
- return $this;
- }
-
- /**
- * Get Margin Left
- *
- * @return int|float
- */
- public function getMarginLeft()
- {
- return $this->marginLeft;
- }
-
- /**
- * Set Margin Left
+ * Get gutter.
*
- * @param int|float $value
- * @return self
- */
- public function setMarginLeft($value = null)
- {
- $this->marginLeft = $this->setNumericVal($value, self::DEFAULT_MARGIN);
-
- return $this;
- }
-
- /**
- * Get Margin Right
- *
- * @return int|float
- */
- public function getMarginRight()
- {
- return $this->marginRight;
- }
-
- /**
- * Set Margin Right
- *
- * @param int|float $value
- * @return self
- */
- public function setMarginRight($value = null)
- {
- $this->marginRight = $this->setNumericVal($value, self::DEFAULT_MARGIN);
-
- return $this;
- }
-
- /**
- * Get Margin Bottom
- *
- * @return int|float
- */
- public function getMarginBottom()
- {
- return $this->marginBottom;
- }
-
- /**
- * Set Margin Bottom
- *
- * @param int|float $value
- * @return self
- */
- public function setMarginBottom($value = null)
- {
- $this->marginBottom = $this->setNumericVal($value, self::DEFAULT_MARGIN);
-
- return $this;
- }
-
- /**
- * Get gutter
- *
- * @return int|float
+ * @return float|int
*/
public function getGutter()
{
@@ -437,9 +327,10 @@ public function getGutter()
}
/**
- * Set gutter
+ * Set gutter.
+ *
+ * @param float|int $value
*
- * @param int|float $value
* @return self
*/
public function setGutter($value = null)
@@ -450,9 +341,9 @@ public function setGutter($value = null)
}
/**
- * Get Header Height
+ * Get Header Height.
*
- * @return int|float
+ * @return float|int
*/
public function getHeaderHeight()
{
@@ -460,9 +351,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)
@@ -473,9 +365,9 @@ public function setHeaderHeight($value = null)
}
/**
- * Get Footer Height
+ * Get Footer Height.
*
- * @return int|float
+ * @return float|int
*/
public function getFooterHeight()
{
@@ -483,9 +375,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)
@@ -496,7 +389,7 @@ public function setFooterHeight($value = null)
}
/**
- * Get page numbering start
+ * Get page numbering start.
*
* @return null|int
*/
@@ -506,9 +399,10 @@ public function getPageNumberingStart()
}
/**
- * Set page numbering start
+ * Set page numbering start.
*
* @param null|int $pageNumberingStart
+ *
* @return self
*/
public function setPageNumberingStart($pageNumberingStart = null)
@@ -519,7 +413,7 @@ public function setPageNumberingStart($pageNumberingStart = null)
}
/**
- * Get Section Columns Count
+ * Get Section Columns Count.
*
* @return int
*/
@@ -529,9 +423,10 @@ public function getColsNum()
}
/**
- * Set Section Columns Count
+ * Set Section Columns Count.
*
* @param int $value
+ *
* @return self
*/
public function setColsNum($value = null)
@@ -542,9 +437,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()
{
@@ -552,9 +447,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)
@@ -565,9 +461,9 @@ public function setColsSpace($value = null)
}
/**
- * Get Break Type
+ * Get Break Type.
*
- * @return string
+ * @return ?string
*/
public function getBreakType()
{
@@ -575,9 +471,10 @@ public function getBreakType()
}
/**
- * Set Break Type
+ * Set Break Type.
*
* @param string $value
+ *
* @return self
*/
public function setBreakType($value = null)
@@ -588,9 +485,9 @@ public function setBreakType($value = null)
}
/**
- * Get line numbering
+ * Get line numbering.
*
- * @return \PhpOffice\PhpWord\Style\LineNumbering
+ * @return LineNumbering
*/
public function getLineNumbering()
{
@@ -598,9 +495,10 @@ public function getLineNumbering()
}
/**
- * Set line numbering
+ * Set line numbering.
*
* @param mixed $value
+ *
* @return self
*/
public function setLineNumbering($value = null)
@@ -611,9 +509,9 @@ public function setLineNumbering($value = null)
}
/**
- * Get vertical alignment
+ * Get vertical alignment.
*
- * @return string
+ * @return ?string
*/
public function getVAlign()
{
@@ -621,9 +519,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..739e56e9de 100644
--- a/src/PhpWord/Style/Shading.php
+++ b/src/PhpWord/Style/Shading.php
@@ -1,4 +1,5 @@
setStyleByArray($style);
}
/**
- * Get pattern
+ * Get pattern.
*
* @return string
*/
@@ -82,24 +85,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 +113,10 @@ public function getColor()
}
/**
- * Set pattern
+ * Set pattern.
*
* @param string $value
+ *
* @return self
*/
public function setColor($value = null)
@@ -122,7 +127,7 @@ public function setColor($value = null)
}
/**
- * Get fill
+ * Get fill.
*
* @return string
*/
@@ -132,9 +137,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..2cdf058117 100644
--- a/src/PhpWord/Style/Shadow.php
+++ b/src/PhpWord/Style/Shadow.php
@@ -1,4 +1,5 @@
setStyleByArray($style);
}
/**
- * Get color
+ * Get color.
*
* @return string
*/
@@ -60,9 +61,10 @@ public function getColor()
}
/**
- * Set color
+ * Set color.
*
* @param string $value
+ *
* @return self
*/
public function setColor($value = null)
@@ -73,7 +75,7 @@ public function setColor($value = null)
}
/**
- * Get offset
+ * Get offset.
*
* @return string
*/
@@ -83,9 +85,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..9f47ff7feb 100644
--- a/src/PhpWord/Style/Shape.php
+++ b/src/PhpWord/Style/Shape.php
@@ -1,4 +1,5 @@
setStyleByArray($style);
}
/**
- * Get points
+ * Get points.
*
* @return string
*/
@@ -103,9 +105,10 @@ public function getPoints()
}
/**
- * Set points
+ * Set points.
*
* @param string $value
+ *
* @return self
*/
public function setPoints($value = null)
@@ -116,9 +119,9 @@ public function setPoints($value = null)
}
/**
- * Get roundness
+ * Get roundness.
*
- * @return int|float
+ * @return float|int
*/
public function getRoundness()
{
@@ -126,9 +129,10 @@ public function getRoundness()
}
/**
- * Set roundness
+ * Set roundness.
+ *
+ * @param float|int $value
*
- * @param int|float $value
* @return self
*/
public function setRoundness($value = null)
@@ -139,9 +143,9 @@ public function setRoundness($value = null)
}
/**
- * Get frame
+ * Get frame.
*
- * @return \PhpOffice\PhpWord\Style\Frame
+ * @return Frame
*/
public function getFrame()
{
@@ -149,9 +153,10 @@ public function getFrame()
}
/**
- * Set frame
+ * Set frame.
*
* @param mixed $value
+ *
* @return self
*/
public function setFrame($value = null)
@@ -162,9 +167,9 @@ public function setFrame($value = null)
}
/**
- * Get fill
+ * Get fill.
*
- * @return \PhpOffice\PhpWord\Style\Fill
+ * @return Fill
*/
public function getFill()
{
@@ -172,9 +177,10 @@ public function getFill()
}
/**
- * Set fill
+ * Set fill.
*
* @param mixed $value
+ *
* @return self
*/
public function setFill($value = null)
@@ -185,9 +191,9 @@ public function setFill($value = null)
}
/**
- * Get outline
+ * Get outline.
*
- * @return \PhpOffice\PhpWord\Style\Outline
+ * @return Outline
*/
public function getOutline()
{
@@ -195,9 +201,10 @@ public function getOutline()
}
/**
- * Set outline
+ * Set outline.
*
* @param mixed $value
+ *
* @return self
*/
public function setOutline($value = null)
@@ -208,9 +215,9 @@ public function setOutline($value = null)
}
/**
- * Get shadow
+ * Get shadow.
*
- * @return \PhpOffice\PhpWord\Style\Shadow
+ * @return Shadow
*/
public function getShadow()
{
@@ -218,9 +225,10 @@ public function getShadow()
}
/**
- * Set shadow
+ * Set shadow.
*
* @param mixed $value
+ *
* @return self
*/
public function setShadow($value = null)
@@ -231,9 +239,9 @@ public function setShadow($value = null)
}
/**
- * Get 3D extrusion
+ * Get 3D extrusion.
*
- * @return \PhpOffice\PhpWord\Style\Extrusion
+ * @return Extrusion
*/
public function getExtrusion()
{
@@ -241,9 +249,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..2ffa40620c 100644
--- a/src/PhpWord/Style/Spacing.php
+++ b/src/PhpWord/Style/Spacing.php
@@ -1,4 +1,5 @@
setStyleByArray($style);
}
/**
- * Get before
+ * Get before.
*
- * @return int|float
+ * @return null|float|int
*/
public function getBefore()
{
@@ -76,9 +77,10 @@ public function getBefore()
}
/**
- * Set before
+ * Set before.
+ *
+ * @param null|float|int $value
*
- * @param int|float $value
* @return self
*/
public function setBefore($value = null)
@@ -89,9 +91,9 @@ public function setBefore($value = null)
}
/**
- * Get after
+ * Get after.
*
- * @return int|float
+ * @return null|float|int
*/
public function getAfter()
{
@@ -99,9 +101,10 @@ public function getAfter()
}
/**
- * Set after
+ * Set after.
+ *
+ * @param null|float|int $value
*
- * @param int|float $value
* @return self
*/
public function setAfter($value = null)
@@ -112,9 +115,9 @@ public function setAfter($value = null)
}
/**
- * Get line
+ * Get line.
*
- * @return int|float
+ * @return null|float|int
*/
public function getLine()
{
@@ -122,9 +125,10 @@ public function getLine()
}
/**
- * Set distance
+ * Set distance.
+ *
+ * @param null|float|int $value
*
- * @param int|float $value
* @return self
*/
public function setLine($value = null)
@@ -135,7 +139,7 @@ public function setLine($value = null)
}
/**
- * Get line rule
+ * Get line rule.
*
* @return string
*/
@@ -145,9 +149,10 @@ public function getLineRule()
}
/**
- * Set line rule
+ * Set line rule.
*
* @param string $value
+ *
* @return self
*/
public function setLineRule($value = null)
@@ -157,31 +162,4 @@ public function setLineRule($value = null)
return $this;
}
-
- /**
- * Get line rule
- *
- * @return string
- * @deprecated Use getLineRule() instead
- * @codeCoverageIgnore
- */
- public function getRule()
- {
- return $this->lineRule;
- }
-
- /**
- * Set line rule
- *
- * @param string $value
- * @return self
- * @deprecated Use setLineRule() instead
- * @codeCoverageIgnore
- */
- public function setRule($value = null)
- {
- $this->lineRule = $value;
-
- return $this;
- }
}
diff --git a/src/PhpWord/Style/TOC.php b/src/PhpWord/Style/TOC.php
index 2efd54a4a4..1efcb6e474 100644
--- a/src/PhpWord/Style/TOC.php
+++ b/src/PhpWord/Style/TOC.php
@@ -1,4 +1,5 @@
type = $this->setEnumVal($type, $stopTypes, $this->type);
$this->position = $this->setNumericVal($position, $this->position);
@@ -94,7 +95,7 @@ public function __construct($type = null, $position = 0, $leader = null)
}
/**
- * Get stop type
+ * Get stop type.
*
* @return string
*/
@@ -104,25 +105,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 +134,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 +162,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..2510a3fa72 100644
--- a/src/PhpWord/Style/Table.php
+++ b/src/PhpWord/Style/Table.php
@@ -1,4 +1,5 @@
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);
}
}
/**
- * @param float|int $cellSpacing
+ * @param null|float|int $cellSpacing
*/
- public function setCellSpacing($cellSpacing = null)
+ public function setCellSpacing($cellSpacing = null): self
{
$this->cellSpacing = $cellSpacing;
+
+ return $this;
}
/**
- * @return float|int
+ * @return null|float|int
*/
public function getCellSpacing()
{
@@ -216,9 +216,9 @@ public function getCellSpacing()
}
/**
- * Set first row
+ * Set first row.
*
- * @return \PhpOffice\PhpWord\Style\Table
+ * @return Table
*/
public function getFirstRow()
{
@@ -226,9 +226,9 @@ public function getFirstRow()
}
/**
- * Get background
+ * Get background.
*
- * @return string
+ * @return ?string
*/
public function getBgColor()
{
@@ -240,39 +240,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 +290,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 +326,7 @@ public function setBorderColor($value = null)
}
/**
- * Get border size inside horizontal
+ * Get border size inside horizontal.
*
* @return int
*/
@@ -333,9 +336,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 +348,7 @@ public function setBorderInsideHSize($value = null)
}
/**
- * Get border color inside horizontal
+ * Get border color inside horizontal.
*
* @return string
*/
@@ -354,9 +358,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 +370,7 @@ public function setBorderInsideHColor($value = null)
}
/**
- * Get border size inside vertical
+ * Get border size inside vertical.
*
* @return int
*/
@@ -375,9 +380,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 +392,7 @@ public function setBorderInsideVSize($value = null)
}
/**
- * Get border color inside vertical
+ * Get border color inside vertical.
*
* @return string
*/
@@ -396,9 +402,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 +414,7 @@ public function setBorderInsideVColor($value = null)
}
/**
- * Get cell margin top
+ * Get cell margin top.
*
* @return int
*/
@@ -417,9 +424,10 @@ public function getCellMarginTop()
}
/**
- * Set cell margin top
+ * Set cell margin top.
*
* @param int $value
+ *
* @return self
*/
public function setCellMarginTop($value = null)
@@ -428,7 +436,7 @@ public function setCellMarginTop($value = null)
}
/**
- * Get cell margin left
+ * Get cell margin left.
*
* @return int
*/
@@ -438,9 +446,10 @@ public function getCellMarginLeft()
}
/**
- * Set cell margin left
+ * Set cell margin left.
*
* @param int $value
+ *
* @return self
*/
public function setCellMarginLeft($value = null)
@@ -449,7 +458,7 @@ public function setCellMarginLeft($value = null)
}
/**
- * Get cell margin right
+ * Get cell margin right.
*
* @return int
*/
@@ -459,9 +468,10 @@ public function getCellMarginRight()
}
/**
- * Set cell margin right
+ * Set cell margin right.
*
* @param int $value
+ *
* @return self
*/
public function setCellMarginRight($value = null)
@@ -470,7 +480,7 @@ public function setCellMarginRight($value = null)
}
/**
- * Get cell margin bottom
+ * Get cell margin bottom.
*
* @return int
*/
@@ -480,9 +490,10 @@ public function getCellMarginBottom()
}
/**
- * Set cell margin bottom
+ * Set cell margin bottom.
*
* @param int $value
+ *
* @return self
*/
public function setCellMarginBottom($value = null)
@@ -491,24 +502,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 +534,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,9 +546,9 @@ public function hasMargin()
}
/**
- * Get shading
+ * Get shading.
*
- * @return \PhpOffice\PhpWord\Style\Shading
+ * @return Shading
*/
public function getShading()
{
@@ -544,9 +556,10 @@ public function getShading()
}
/**
- * Set shading
+ * Set shading.
*
* @param mixed $value
+ *
* @return self
*/
public function setShading($value = null)
@@ -583,35 +596,9 @@ public function setAlignment($value)
}
/**
- * @deprecated 0.13.0 Use the `getAlignment` method instead.
+ * Get width.
*
- * @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
- *
- * @return int|float
+ * @return float|int
*/
public function getWidth()
{
@@ -619,9 +606,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 +620,7 @@ public function setWidth($value = null)
}
/**
- * Get width unit
+ * Get width unit.
*
* @return string
*/
@@ -642,9 +630,10 @@ public function getUnit()
}
/**
- * Set width unit
+ * Set width unit.
*
* @param string $value
+ *
* @return self
*/
public function setUnit($value = null)
@@ -656,7 +645,7 @@ public function setUnit($value = null)
}
/**
- * Get layout
+ * Get layout.
*
* @return string
*/
@@ -666,27 +655,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 +689,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 +697,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,9 +714,9 @@ private function setTableOnlyProperty($property, $value, $isNumeric = true)
}
/**
- * Get position
+ * Get position.
*
- * @return \PhpOffice\PhpWord\Style\TablePosition
+ * @return ?TablePosition
*/
public function getPosition()
{
@@ -732,9 +724,10 @@ public function getPosition()
}
/**
- * Set position
+ * Set position.
*
* @param mixed $value
+ *
* @return self
*/
public function setPosition($value = null)
@@ -745,7 +738,7 @@ public function setPosition($value = null)
}
/**
- * @return TblWidthComplexType
+ * @return ?TblWidthComplexType
*/
public function getIndent()
{
@@ -753,8 +746,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 +758,7 @@ public function setIndent(TblWidthComplexType $indent)
}
/**
- * Get the columnWidths
+ * Get the columnWidths.
*
* @return null|int[]
*/
@@ -775,30 +768,31 @@ 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
+ * @return ?bool
*/
public function isBidiVisual()
{
- return $this->bidiVisual;
+ return $this->bidiVisual ?? Settings::isDefaultRtl();
}
/**
- * Set bidiVisual
+ * Set bidiVisual.
*
- * @param bool $bidi
+ * @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..deec49dfe3 100644
--- a/src/PhpWord/Style/TablePosition.php
+++ b/src/PhpWord/Style/TablePosition.php
@@ -1,4 +1,5 @@
setStyleByArray($style);
}
/**
- * Get distance from left of table to text
+ * Get distance from left of table to text.
*
* @return int
*/
@@ -164,9 +173,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 +187,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 +197,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 +211,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 +221,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 +235,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 +245,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 +259,7 @@ public function setBottomFromText($value = null)
}
/**
- * Get table vertical anchor
+ * Get table vertical anchor.
*
* @return string
*/
@@ -256,25 +269,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 +298,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 +327,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 +358,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 +372,7 @@ public function setTblpX($value = null)
}
/**
- * Get relative vertical alignment from anchor
+ * Get relative vertical alignment from anchor.
*
* @return string
*/
@@ -365,28 +382,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 +414,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..82fe7a95c4 100644
--- a/src/PhpWord/Style/TextBox.php
+++ b/src/PhpWord/Style/TextBox.php
@@ -1,147 +1,153 @@
bgColor = $value;
+ }
+
+ /**
+ * Get background color.
+ */
+ public function getBgColor(): ?string
+ {
+ return $this->bgColor;
+ }
+
+ /**
+ * Set margin top.
*/
- public function setInnerMarginTop($value = null)
+ public function setInnerMarginTop(?int $value = null): void
{
$this->innerMarginTop = $value;
}
/**
- * Get margin top
- *
- * @return int
+ * Get margin top.
*/
- public function getInnerMarginTop()
+ public function getInnerMarginTop(): ?int
{
return $this->innerMarginTop;
}
/**
* Set margin left.
- *
- * @param int $value
*/
- public function setInnerMarginLeft($value = null)
+ public function setInnerMarginLeft(?int $value = null): void
{
$this->innerMarginLeft = $value;
}
/**
- * Get margin left
- *
- * @return int
+ * Get margin left.
*/
- public function getInnerMarginLeft()
+ public function getInnerMarginLeft(): ?int
{
return $this->innerMarginLeft;
}
/**
* Set margin right.
- *
- * @param int $value
*/
- public function setInnerMarginRight($value = null)
+ public function setInnerMarginRight(?int $value = null): void
{
$this->innerMarginRight = $value;
}
/**
- * Get margin right
- *
- * @return int
+ * Get margin right.
*/
- public function getInnerMarginRight()
+ public function getInnerMarginRight(): ?int
{
return $this->innerMarginRight;
}
/**
* Set margin bottom.
- *
- * @param int $value
*/
- public function setInnerMarginBottom($value = null)
+ public function setInnerMarginBottom(?int $value = null): void
{
$this->innerMarginBottom = $value;
}
/**
- * Get margin bottom
- *
- * @return int
+ * Get margin bottom.
*/
- public function getInnerMarginBottom()
+ public function getInnerMarginBottom(): ?int
{
return $this->innerMarginBottom;
}
@@ -149,9 +155,9 @@ public function getInnerMarginBottom()
/**
* Set TLRB cell margin.
*
- * @param int $value Margin in twips
+ * @param null|int $value Margin in twips
*/
- public function setInnerMargin($value = null)
+ public function setInnerMargin(?int $value = null): void
{
$this->setInnerMarginTop($value);
$this->setInnerMarginLeft($value);
@@ -160,26 +166,24 @@ public function setInnerMargin($value = null)
}
/**
- * Get cell margin
+ * Get cell margin.
*
* @return int[]
*/
- public function getInnerMargin()
+ public function getInnerMargin(): array
{
- return array($this->innerMarginLeft, $this->innerMarginTop, $this->innerMarginRight, $this->innerMarginBottom);
+ return [$this->innerMarginLeft, $this->innerMarginTop, $this->innerMarginRight, $this->innerMarginBottom];
}
/**
* Has inner margin?
- *
- * @return bool
*/
- public function hasInnerMargins()
+ public function hasInnerMargins(): bool
{
$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;
}
@@ -191,39 +195,33 @@ public function hasInnerMargins()
/**
* Set border size.
*
- * @param int $value Size in points
+ * @param null|int $value Size in points
*/
- public function setBorderSize($value = null)
+ public function setBorderSize(?int $value = null): void
{
$this->borderSize = $value;
}
/**
- * Get border size
- *
- * @return int
+ * Get border size.
*/
- public function getBorderSize()
+ public function getBorderSize(): ?int
{
return $this->borderSize;
}
/**
* Set border color.
- *
- * @param string $value
*/
- public function setBorderColor($value = null)
+ public function setBorderColor(?string $value = null): void
{
$this->borderColor = $value;
}
/**
- * Get border color
- *
- * @return string
+ * Get border color.
*/
- public function getBorderColor()
+ public function getBorderColor(): ?string
{
return $this->borderColor;
}
diff --git a/src/PhpWord/TemplateProcessor.php b/src/PhpWord/TemplateProcessor.php
index 7efc0f1ac8..073393ffc4 100644
--- a/src/PhpWord/TemplateProcessor.php
+++ b/src/PhpWord/TemplateProcessor.php
@@ -1,4 +1,5 @@
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());
$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()
+ {
+ // ZipClass
+ if ($this->zipClass) {
+ try {
+ $this->zipClass->close();
+ } catch (Throwable $e) {
+ // Nothing to do here.
+ }
+ }
}
/**
- * 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");
*
- * @return \PhpOffice\PhpWord\Shared\ZipArchive
+ * @return ZipArchive
*/
public function zip()
{
@@ -162,16 +182,16 @@ protected function readPartWithRels($fileName)
/**
* @param string $xml
- * @param \XSLTProcessor $xsltProcessor
- *
- * @throws \PhpOffice\PhpWord\Exception\Exception
+ * @param XSLTProcessor $xsltProcessor
*
* @return string
*/
protected function transformSingleXml($xml, $xsltProcessor)
{
- $orignalLibEntityLoader = libxml_disable_entity_loader(true);
- $domDocument = new \DOMDocument();
+ 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,14 +200,16 @@ 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;
}
/**
* @param mixed $xml
- * @param \XSLTProcessor $xsltProcessor
+ * @param XSLTProcessor $xsltProcessor
*
* @return mixed
*/
@@ -211,15 +233,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)) {
@@ -238,42 +258,42 @@ public function applyXslStyleSheet($xslDomDocument, $xslOptions = array(), $xslO
*/
protected static function ensureMacroCompleted($macro)
{
- if (substr($macro, 0, 2) !== '${' && substr($macro, -1) !== '}') {
- $macro = '${' . $macro . '}';
+ if (substr($macro, 0, 2) !== self::$macroOpeningChars && substr($macro, -1) !== self::$macroClosingChars) {
+ $macro = self::$macroOpeningChars . $macro . self::$macroClosingChars;
}
return $macro;
}
/**
- * @param string $subject
+ * @param ?string $subject
*
* @return string
*/
protected static function ensureUtf8Encoded($subject)
{
- if (!Text::isUTF8($subject)) {
- $subject = utf8_encode($subject);
- }
-
- return $subject;
+ return (null !== $subject) ? Text::toUTF8($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;
$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();
$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');
@@ -284,15 +304,14 @@ 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;
$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();
@@ -300,11 +319,11 @@ public function setComplexBlock($search, \PhpOffice\PhpWord\Element\AbstractElem
}
/**
- * @param mixed $search
- * @param mixed $replace
+ * @param array|string $search
+ * @param null|array|bool|float|int|string $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) {
@@ -321,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()) {
@@ -329,6 +348,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);
@@ -336,44 +364,105 @@ 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, int $limit = self::MAXIMUM_REPLACEMENTS_DEFAULT): void
{
foreach ($values as $macro => $replace) {
- $this->setValue($macro, $replace);
+ $this->setValue($macro, $replace, $limit);
}
}
+ 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
+ */
+ 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;
+
+ // Get the next relation id
+ $rId = $this->getNextRelationsIndex($this->getMainPartName());
+ $chart->setRelationId($rId);
+
+ // Define the chart filename
+ $filename = "charts/chart{$rId}.xml";
+
+ // Get the part writer
+ $writerPart = new 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);
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;
}
}
@@ -385,13 +474,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', $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)) {
@@ -401,7 +490,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;
@@ -411,22 +500,24 @@ 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);
- $width = $widthFloat . $matches[1];
+ $matches = [];
+ preg_match('/\\d([a-z%]+)$/', $height, $matches);
+ $width = $widthFloat . (!empty($matches) ? $matches[1] : 'px');
} 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];
+ $matches = [];
+ preg_match('/\\d([a-z%]+)$/', $width, $matches);
+ $height = $heightFloat . (!empty($matches) ? $matches[1] : 'px');
} 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]) {
+ if (!empty($widthMatches)
+ && !empty($heightMatches)
+ && $widthMatches[1] == $heightMatches[1]) {
$dimention = $widthMatches[1];
$widthFloat = (float) $width;
$heightFloat = (float) $height;
@@ -447,6 +538,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'])) {
@@ -462,46 +560,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])) {
@@ -520,11 +618,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
@@ -543,46 +641,47 @@ 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(
- $this->getMainPartName() => &$this->tempDocumentMainPart,
- );
+ $searchParts = [
+ $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];
+ foreach (array_keys($this->tempDocumentFooters) as $footerIndex) {
+ $searchParts[$this->getFooterName($footerIndex)] = &$this->tempDocumentFooters[$footerIndex];
}
// 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) {
$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);
+ return ($partVar == $searchString) || preg_match('/^' . preg_quote($searchString, '/') . ':/', $partVar);
});
foreach ($varsToReplace as $varNameWithArgs) {
@@ -596,19 +695,23 @@ 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();
- if (preg_match('/(<[^<]+>)([^<]*)(' . preg_quote($varNameWithArgsFixed) . ')([^>]*)(<[^>]+>)/Uu', $partContent, $matches)) {
+ $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);
}
+
+ if (++$i >= $limit) {
+ break;
+ }
}
}
}
@@ -655,10 +758,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);
@@ -687,7 +788,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)
+ ) {
break;
}
// This row was a spanned row, update $rowEnd and search for the next row.
@@ -697,19 +799,83 @@ 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;
}
+ /**
+ * Delete a table row in a template document.
+ */
+ public function deleteRow(string $search): void
+ {
+ if (self::$macroOpeningChars !== substr($search, 0, 2) && self::$macroClosingChars !== substr($search, -1)) {
+ $search = self::$macroOpeningChars . $search . self::$macroClosingChars;
+ }
+
+ $tagPos = strpos($this->tempDocumentMainPart, $search);
+ if (!$tagPos) {
+ throw new Exception(sprintf('Can not delete row %s, template variable not found or variable contains markup.', $search));
+ }
+
+ $tableStart = $this->findTableStart($tagPos);
+ $tableEnd = $this->findTableEnd($tagPos);
+ $xmlTable = $this->getSlice($tableStart, $tableEnd);
+
+ if (substr_count($xmlTable, 'tempDocumentMainPart = $this->getSlice(0, $tableStart) . $this->getSlice($tableEnd);
+
+ return;
+ }
+
+ $rowStart = $this->findRowStart($tagPos);
+ $rowEnd = $this->findRowEnd($tagPos);
+ $xmlRow = $this->getSlice($rowStart, $rowEnd);
+
+ $this->tempDocumentMainPart = $this->getSlice(0, $rowStart) . $this->getSlice($rowEnd);
+
+ // Check if there's a cell spanning multiple rows.
+ if (preg_match('# #', $xmlRow)) {
+ $extraRowStart = $rowStart;
+ while (true) {
+ $extraRowStart = $this->findRowStart($extraRowStart + 1);
+ $extraRowEnd = $this->findRowEnd($extraRowStart + 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)
+ ) {
+ break;
+ }
+
+ $tableStart = $this->findTableStart($extraRowEnd + 1);
+ $tableEnd = $this->findTableEnd($extraRowEnd + 1);
+ $xmlTable = $this->getSlice($tableStart, $tableEnd);
+ if (substr_count($xmlTable, 'tempDocumentMainPart = $this->getSlice(0, $tableStart) . $this->getSlice($tableEnd);
+
+ return;
+ }
+
+ $this->tempDocumentMainPart = $this->getSlice(0, $extraRowStart) . $this->getSlice($extraRowEnd);
+ }
+ }
+ }
+
/**
* Clones a table row and populates it's values from a two-dimensional array in a template document.
*
* @param string $search
* @param array $values
*/
- public function cloneRowAndSetValues($search, $values)
+ public function cloneRowAndSetValues($search, $values): void
{
$this->cloneRow($search, count($values));
@@ -730,14 +896,18 @@ 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 = [];
+ $escapedMacroOpeningChars = self::$macroOpeningChars;
+ $escapedMacroClosingChars = self::$macroClosingChars;
preg_match(
- '/(<\?xml.*)(\${' . $blockname . '}<\/w:.*?p>)(.*)()/is',
+ //'/(.*((?s)))(.*)((?s))/is',
+ '/(.*((?s)))(.*)((?s))/is',
+ //'/(.*((?s)))(.*)((?s))/is',
$this->tempDocumentMainPart,
$matches
);
@@ -749,8 +919,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;
}
}
@@ -773,11 +943,13 @@ 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 = [];
+ $escapedMacroOpeningChars = preg_quote(self::$macroOpeningChars);
+ $escapedMacroClosingChars = preg_quote(self::$macroClosingChars);
preg_match(
- '/(<\?xml.*)(\${' . $blockname . '}<\/w:.*?p>)(.*)()/is',
+ '/(<\?xml.*)(' . $escapedMacroOpeningChars . $blockname . $escapedMacroClosingChars . '<\/w:.*?p>)(.*)()/is',
$this->tempDocumentMainPart,
$matches
);
@@ -796,20 +968,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 {
@@ -820,8 +992,6 @@ public function setUpdateFields($update = true)
/**
* Saves the result document.
*
- * @throws \PhpOffice\PhpWord\Exception\Exception
- *
* @return string
*/
public function save()
@@ -851,7 +1021,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])) {
@@ -867,7 +1037,7 @@ protected function savePartWithRels($fileName, $xml)
*
* @param string $fileName
*/
- public function saveAs($fileName)
+ public function saveAs($fileName): void
{
$tempFileName = $this->save();
@@ -895,8 +1065,12 @@ public function saveAs($fileName)
*/
protected function fixBrokenMacros($documentPart)
{
+ $brokenMacroOpeningChars = substr(self::$macroOpeningChars, 0, 1);
+ $endMacroOpeningChars = substr(self::$macroOpeningChars, 1);
+ $macroClosingChars = self::$macroClosingChars;
+
return preg_replace_callback(
- '/\$(?:\{|[^{$]*\>\{)[^}$]*\}/U',
+ '/\\' . $brokenMacroOpeningChars . '(?:\\' . $endMacroOpeningChars . '|[^{$]*\>\{)[^' . $macroClosingChars . '$]*\}/U',
function ($match) {
return strip_tags($match[0]);
},
@@ -907,12 +1081,12 @@ function ($match) {
/**
* Find and replace macros in the given XML section.
*
- * @param mixed $search
- * @param mixed $replace
- * @param string $documentPartXML
+ * @param array|string $search
+ * @param array|string $replace
+ * @param array|string $documentPartXML
* @param int $limit
*
- * @return string
+ * @return ($documentPartXML is string ? string : array)
*/
protected function setValueForPart($search, $replace, $documentPartXML, $limit)
{
@@ -934,8 +1108,11 @@ protected function setValueForPart($search, $replace, $documentPartXML, $limit)
*/
protected function getVariablesForPart($documentPartXML)
{
- $matches = array();
- preg_match_all('/\$\{(.*?)}/i', $documentPartXML, $matches);
+ $matches = [];
+ $escapedMacroOpeningChars = preg_quote(self::$macroOpeningChars);
+ $escapedMacroClosingChars = preg_quote(self::$macroClosingChars);
+
+ preg_match_all("/$escapedMacroOpeningChars(.*?)$escapedMacroClosingChars/i", $documentPartXML, $matches);
return $matches[1];
}
@@ -963,14 +1140,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
*/
@@ -1006,7 +1183,12 @@ 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;
@@ -1020,13 +1202,44 @@ protected function getDocumentContentTypesName()
return '[Content_Types].xml';
}
+ /**
+ * Find the start position of the nearest table before $offset.
+ */
+ private function findTableStart(int $offset): int
+ {
+ $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 table.');
+ }
+
+ return $rowStart;
+ }
+
+ /**
+ * Find the end position of the nearest table row after $offset.
+ */
+ private function findTableEnd(int $offset): int
+ {
+ return strpos($this->tempDocumentMainPart, ' ', $offset) + 7;
+ }
+
/**
* Find the start position of the nearest table row before $offset.
*
* @param int $offset
*
- * @throws \PhpOffice\PhpWord\Exception\Exception
- *
* @return int
*/
protected function findRowStart($offset)
@@ -1074,25 +1287,36 @@ 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
*
- * @return string
+ * @return array
*/
protected function indexClonedVariables($count, $xmlBlock)
{
- $results = array();
- for ($i = 1; $i <= $count; $i++) {
- $results[] = preg_replace('/\$\{(.*?)\}/', '\${\\1#' . $i . '}', $xmlBlock);
+ $results = [];
+ $escapedMacroOpeningChars = preg_quote(self::$macroOpeningChars);
+ $escapedMacroClosingChars = preg_quote(self::$macroClosingChars);
+
+ for ($i = 1; $i <= $count; ++$i) {
+ $results[] = preg_replace("/$escapedMacroOpeningChars([^:]*?)(:.*?)?$escapedMacroClosingChars/", self::$macroOpeningChars . '\1#' . $i . '\2' . self::$macroClosingChars, $xmlBlock);
}
return $results;
}
/**
- * Raplaces variables with values from array, array keys are the variable names
+ * 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.
*
* @param array $variableReplacements
* @param string $xmlBlock
@@ -1101,7 +1325,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) {
@@ -1114,14 +1338,15 @@ 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
+ *
+ * @return 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)) {
@@ -1133,12 +1358,13 @@ protected 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')
@@ -1157,11 +1383,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 $
*
@@ -1169,6 +1395,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)
@@ -1180,10 +1407,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)
@@ -1201,10 +1429,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)
@@ -1216,9 +1445,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)
@@ -1226,7 +1456,7 @@ protected function splitTextIntoTexts($text)
if (!$this->textNeedsSplitting($text)) {
return $text;
}
- $matches = array();
+ $matches = [];
if (preg_match('/()/i', $text, $matches)) {
$extractedStyle = $matches[0];
} else {
@@ -1234,19 +1464,44 @@ protected function splitTextIntoTexts($text)
}
$unformattedText = preg_replace('/>\s+', '><', $text);
- $result = str_replace(array('${', '}'), array(' ' . $extractedStyle . '${', '} ' . $extractedStyle . ''), $unformattedText);
+ $result = str_replace([self::$macroOpeningChars, self::$macroClosingChars], [' ' . $extractedStyle . '' . self::$macroOpeningChars, self::$macroClosingChars . ' ' . $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)
{
- return preg_match('/[^>]\${|}[^<]/i', $text) == 1;
+ $escapedMacroOpeningChars = preg_quote(self::$macroOpeningChars);
+ $escapedMacroClosingChars = preg_quote(self::$macroClosingChars);
+
+ return 1 === preg_match('/[^>]' . $escapedMacroOpeningChars . '|' . $escapedMacroClosingChars . '[^<]/i', $text);
+ }
+
+ public function setMacroOpeningChars(string $macroOpeningChars): void
+ {
+ self::$macroOpeningChars = $macroOpeningChars;
+ }
+
+ public function setMacroClosingChars(string $macroClosingChars): void
+ {
+ self::$macroClosingChars = $macroClosingChars;
+ }
+
+ public function setMacroChars(string $macroOpeningChars, string $macroClosingChars): void
+ {
+ self::$macroOpeningChars = $macroOpeningChars;
+ self::$macroClosingChars = $macroClosingChars;
+ }
+
+ public function getTempDocumentFilename(): string
+ {
+ return $this->tempDocumentFilename;
}
}
diff --git a/src/PhpWord/Writer/AbstractWriter.php b/src/PhpWord/Writer/AbstractWriter.php
index 2c1ad29460..13859d8227 100644
--- a/src/PhpWord/Writer/AbstractWriter.php
+++ b/src/PhpWord/Writer/AbstractWriter.php
@@ -1,4 +1,5 @@
'', '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
+ * @return 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 +121,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 +137,7 @@ public function getWriterPart($partName = '')
}
/**
- * Get use disk caching status
+ * Get use disk caching status.
*
* @return bool
*/
@@ -146,19 +147,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 +170,7 @@ public function setUseDiskCaching($value = false, $directory = null)
}
/**
- * Get disk caching directory
+ * Get disk caching directory.
*
* @return string
*/
@@ -180,7 +180,7 @@ public function getDiskCachingDirectory()
}
/**
- * Get temporary directory
+ * Get temporary directory.
*
* @return string
*/
@@ -190,9 +190,10 @@ public function getTempDir()
}
/**
- * Set temporary directory
+ * Set temporary directory.
*
* @param string $value
+ *
* @return self
*/
public function setTempDir($value)
@@ -206,11 +207,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 +235,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 +254,7 @@ protected function cleanupTempFile()
/**
* Clear temporary directory.
*/
- protected function clearTempDir()
+ protected function clearTempDir(): void
{
if (is_dir($this->tempDir)) {
$this->deleteDir($this->tempDir);
@@ -262,13 +262,11 @@ protected function clearTempDir()
}
/**
- * Get ZipArchive object
+ * Get ZipArchive object.
*
* @param string $filename
*
- * @throws \Exception
- *
- * @return \PhpOffice\PhpWord\Shared\ZipArchive
+ * @return ZipArchive
*/
protected function getZipArchive($filename)
{
@@ -293,20 +291,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 +321,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 +331,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
@@ -351,17 +346,8 @@ 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();
- ob_end_clean();
+ $imageContents = $element['imageString'];
$zip->addFromString($target, $imageContents);
- imagedestroy($image);
} else {
$this->addFileToPackage($zip, $element['source'], $target);
}
@@ -373,17 +359,17 @@ protected function addFilesToPackage(ZipArchive $zip, $elements)
*
* Get the actual source from an archive image.
*
- * @param \PhpOffice\PhpWord\Shared\ZipArchive $zipPackage
+ * @param ZipArchive $zipPackage
* @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 +383,7 @@ protected function addFileToPackage($zipPackage, $source, $target)
$actualSource = $source;
}
- if (!is_null($actualSource)) {
+ if (null !== $actualSource) {
$zipPackage->addFile($actualSource, $target);
}
}
@@ -407,7 +393,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 === '..') {
@@ -421,16 +407,4 @@ private function deleteDir($dir)
rmdir($dir);
}
-
- /**
- * Get use disk caching status
- *
- * @deprecated 0.10.0
- *
- * @codeCoverageIgnore
- */
- public function getUseDiskCaching()
- {
- return $this->isUseDiskCaching();
- }
}
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 @@
+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 @@
+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 @@
+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 @@
+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 @@
+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..74143a30ef
--- /dev/null
+++ b/src/PhpWord/Writer/EPub3/Part/ContentXhtml.php
@@ -0,0 +1,118 @@
+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(AbstractElement $textElement, XMLWriter $xmlWriter): void
+ {
+ if ($textElement instanceof Text) {
+ $text = $textElement->getText();
+ if ($text !== null) {
+ $xmlWriter->text((string) $text);
+ }
+ } elseif (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/tests/PhpWord/Reader/ODTextTest.php b/src/PhpWord/Writer/EPub3/Part/Manifest.php
similarity index 53%
rename from tests/PhpWord/Reader/ODTextTest.php
rename to src/PhpWord/Writer/EPub3/Part/Manifest.php
index ad27086495..fcb0d1f428 100644
--- a/tests/PhpWord/Reader/ODTextTest.php
+++ b/src/PhpWord/Writer/EPub3/Part/Manifest.php
@@ -1,4 +1,5 @@
assertInstanceOf('PhpOffice\\PhpWord\\PhpWord', $phpWord);
+ $content = '';
+ $content .= '';
+ $content .= '';
+ $content .= ' ';
+ $content .= ' ';
+ $content .= ' ';
+
+ 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 @@
+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('' . htmlspecialchars($title, ENT_QUOTES) . ' ');
+ $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/Template.php b/src/PhpWord/Writer/EPub3/Part/Mimetype.php
similarity index 72%
rename from src/PhpWord/Template.php
rename to src/PhpWord/Writer/EPub3/Part/Mimetype.php
index c42696f08c..8e5b7d41ba 100644
--- a/src/PhpWord/Template.php
+++ b/src/PhpWord/Writer/EPub3/Part/Mimetype.php
@@ -1,4 +1,5 @@
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 @@
+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 @@
+setPhpWord($phpWord);
- $this->parts = array('Head', 'Body');
+ $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 \PhpOffice\PhpWord\Writer\HTML\Part\AbstractPart $part Type hint */
+ /** @var AbstractPart $part Type hint */
$part = new $partClass();
$part->setParentWriter($this);
$this->writerParts[strtolower($partName)] = $part;
@@ -62,20 +88,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(string $filename): void
{
$this->writeFile($this->openFile($filename), $this->getContent());
}
/**
- * Get content
+ * Get content.
*
* @return string
+ *
* @since 0.11.0
*/
public function getContent()
@@ -84,16 +107,58 @@ public function getContent()
$content .= '' . PHP_EOL;
$content .= '' . PHP_EOL;
- $content .= '' . PHP_EOL;
+ $langtext = '';
+ $phpWord = $this->getPhpWord();
+ $lang = $phpWord->getSettings()->getThemeFontLang();
+ if (!empty($lang)) {
+ $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;
+ // Trigger a callback for editing the entire HTML
+ $callback = $this->editCallback;
+ if ($callback !== null) {
+ $content = $callback($content);
+ }
+
return $content;
}
/**
- * Get is PDF
+ * 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 setEditCallback(?callable $callback): self
+ {
+ $this->editCallback = $callback;
+
+ return $this;
+ }
+
+ /**
+ * Get is PDF.
*
* @return bool
*/
@@ -103,7 +168,7 @@ public function isPdf()
}
/**
- * Get notes
+ * Get notes.
*
* @return array
*/
@@ -118,22 +183,56 @@ 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
- *
- * @deprecated 0.11.0
- *
- * @return string
- *
- * @codeCoverageIgnore
+ * 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 writeDocument()
+ public function setDefaultWhiteSpace(string $value): self
{
- return $this->getContent();
+ $this->defaultWhiteSpace = Validate::validateCSSWhiteSpace($value);
+
+ return $this;
+ }
+
+ /**
+ * Escape string or not depending on setting.
+ */
+ public function escapeHTML(string $txt): string
+ {
+ if (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 dc5ccfaadc..0e6a112eed 100644
--- a/src/PhpWord/Writer/HTML/Element/AbstractElement.php
+++ b/src/PhpWord/Writer/HTML/Element/AbstractElement.php
@@ -1,4 +1,5 @@
parentWriter = $parentWriter;
$this->element = $element;
$this->withoutP = $withoutP;
- $this->escaper = new Escaper();
}
/**
@@ -79,7 +71,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..55a8c22e27 100644
--- a/src/PhpWord/Writer/HTML/Element/Bookmark.php
+++ b/src/PhpWord/Writer/HTML/Element/Bookmark.php
@@ -1,4 +1,5 @@
getElements();
@@ -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 2252dc3af8..7e7f31d4fc 100644
--- a/src/PhpWord/Writer/HTML/Element/Endnote.php
+++ b/src/PhpWord/Writer/HTML/Element/Endnote.php
@@ -1,4 +1,5 @@
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 .= "parentWriter->escapeHTML($this->element->getSource())
+ . '">'
+ . $this->parentWriter->escapeHTML($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 384b3ef165..232a894a59 100644
--- a/src/PhpWord/Writer/HTML/Element/ListItem.php
+++ b/src/PhpWord/Writer/HTML/Element/ListItem.php
@@ -1,4 +1,5 @@
' . $this->escaper->escapeHtml($this->element->getTextObject()->getText()) . '' . PHP_EOL;
- } else {
- $content = '' . $this->element->getTextObject()->getText() . '
' . PHP_EOL;
- }
+ $content = '' . $this->parentWriter->escapeHTML($this->element->getTextObject()->getText()) . '
' . PHP_EOL;
return $content;
}
diff --git a/tests/PhpWord/Writer/HTML/PartTest.php b/src/PhpWord/Writer/HTML/Element/ListItemRun.php
similarity index 59%
rename from tests/PhpWord/Writer/HTML/PartTest.php
rename to src/PhpWord/Writer/HTML/Element/ListItemRun.php
index f83034143c..a708868c3d 100644
--- a/tests/PhpWord/Writer/HTML/PartTest.php
+++ b/src/PhpWord/Writer/HTML/Element/ListItemRun.php
@@ -1,4 +1,5 @@
getParentWriter();
+ if (!$this->element instanceof \PhpOffice\PhpWord\Element\ListItemRun) {
+ return '';
+ }
+
+ $writer = new Container($this->parentWriter, $this->element);
+ $content = $writer->write() . PHP_EOL;
+
+ return $content;
}
}
diff --git a/src/PhpWord/Writer/HTML/Element/PageBreak.php b/src/PhpWord/Writer/HTML/Element/PageBreak.php
index f9998e3793..60335591c5 100644
--- a/src/PhpWord/Writer/HTML/Element/PageBreak.php
+++ b/src/PhpWord/Writer/HTML/Element/PageBreak.php
@@ -1,4 +1,5 @@
parentWriter;
+ if ($parentWriter instanceof TCPDF) {
+ return ' ';
+ }
if ($parentWriter->isPdf()) {
return ' ';
}
- return '';
+ return '
' . PHP_EOL;
}
}
diff --git a/src/PhpWord/Writer/HTML/Element/Ruby.php b/src/PhpWord/Writer/HTML/Element/Ruby.php
new file mode 100644
index 0000000000..5648d85e2f
--- /dev/null
+++ b/src/PhpWord/Writer/HTML/Element/Ruby.php
@@ -0,0 +1,126 @@
+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 = "getParagraphStyleForTextRun($element->getBaseTextRun(), $rubyTagPropertyCSS)} lang=\"{$lang}\">";
+ $content .= $baseText;
+ $content .= ' ( ';
+ $rtTagPropertyCSS = $this->getPropertyCssForRtTag($element->getProperties());
+ $content .= "getParagraphStyleForTextRun($element->getRubyTextRun(), $rtTagPropertyCSS)}>";
+ $content .= $rubyText;
+ $content .= ' ';
+ $content .= ') ';
+ $content .= ' ';
+
+ return $content;
+ }
+
+ /**
+ * Get property CSS for the 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 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 = '';
+ $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/HTML/Element/Table.php b/src/PhpWord/Writer/HTML/Element/Table.php
index a6f14792f8..b66e2f8c92 100644
--- a/src/PhpWord/Writer/HTML/Element/Table.php
+++ b/src/PhpWord/Writer/HTML/Element/Table.php
@@ -1,4 +1,5 @@
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 $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 .= '' . 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();
+ $cellStyleCss = $this->getTableStyle($cellStyle);
$cellBgColor = $cellStyle->getBgColor();
$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));
@@ -62,42 +66,27 @@ 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])) {
- if ($kRowCells[$j]->getStyle()->getVMerge() === 'continue') {
- $cellRowSpan++;
- } else {
- break;
- }
- } else {
- break;
- }
- }
+ $cellRowSpan = $this->calculateCellRowSpan($rows, $i, $j);
}
// 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}\"" : '');
- $cellBgColorAttr = (is_null($cellBgColor) ? '' : " bgcolor=\"#{$cellBgColor}\"");
- $cellFgColorAttr = (is_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++) {
+ 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;
}
@@ -115,27 +104,79 @@ public function write()
}
/**
- * Translates Table style in CSS equivalent
+ * Translates Table style in CSS equivalent.
*
- * @param string|\PhpOffice\PhpWord\Style\Table|null $tableStyle
- * @return string
+ * @param null|\PhpOffice\PhpWord\Style\Cell|\PhpOffice\PhpWord\Style\Table|string $tableStyle
*/
- private function getTableStyle($tableStyle = null)
+ private function getTableStyle($tableStyle = null): string
{
if ($tableStyle == null) {
return '';
}
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 ' class="' . $tableStyle . '"';
+ }
+
+ $styleWriter = new TableStyleWriter($tableStyle);
+ $style = $styleWriter->write();
+ if ($style === '') {
+ return '';
+ }
+
+ 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 $style . '"';
+ return $rowSpan;
}
}
diff --git a/src/PhpWord/Writer/HTML/Element/Text.php b/src/PhpWord/Writer/HTML/Element/Text.php
index 04d76a8327..7be95a5c76 100644
--- a/src/PhpWord/Writer/HTML/Element/Text.php
+++ b/src/PhpWord/Writer/HTML/Element/Text.php
@@ -1,4 +1,5 @@
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;
- if (Settings::isOutputEscapingEnabled()) {
- $content .= $this->escaper->escapeHtml($element->getText());
- } else {
- $content .= $element->getText();
- }
+ $content .= $text;
$content .= $this->closingTags;
$content .= $this->closingText;
$content .= $this->writeClosing();
@@ -91,7 +95,7 @@ public function write()
*
* @param string $value
*/
- public function setOpeningText($value)
+ public function setOpeningText($value): void
{
$this->openingText = $value;
}
@@ -101,13 +105,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
*/
@@ -115,10 +119,7 @@ protected function writeOpening()
{
$content = '';
if (!$this->withoutP) {
- $style = '';
- if (method_exists($this->element, 'getParagraphStyle')) {
- $style = $this->getParagraphStyle();
- }
+ $style = $this->getParagraphStyle();
$content .= "";
}
@@ -129,7 +130,7 @@ protected function writeOpening()
}
/**
- * Write ending
+ * Write ending.
*
* @return string
*/
@@ -141,12 +142,7 @@ protected function writeClosing()
$content .= $this->writeTrackChangeClosing();
if (!$this->withoutP) {
- if (Settings::isOutputEscapingEnabled()) {
- $content .= $this->escaper->escapeHtml($this->closingText);
- } else {
- $content .= $this->closingText;
- }
-
+ $content .= $this->parentWriter->escapeHTML($this->closingText);
$content .= '
' . PHP_EOL;
}
@@ -154,7 +150,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 +168,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 +185,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 +207,7 @@ private function writeTrackChangeClosing()
}
/**
- * Write paragraph style
+ * Write paragraph style.
*
* @return string
*/
@@ -228,6 +224,7 @@ private function getParagraphStyle()
$pStyleIsObject = ($paragraphStyle instanceof Paragraph);
if ($pStyleIsObject) {
$styleWriter = new ParagraphStyleWriter($paragraphStyle);
+ $styleWriter->setParentWriter($this->parentWriter);
$style = $styleWriter->write();
} elseif (is_string($paragraphStyle)) {
$style = $paragraphStyle;
@@ -243,22 +240,50 @@ private function getParagraphStyle()
/**
* Get font style.
*/
- private function getFontStyle()
+ private function processFontStyle(): void
{
/** @var \PhpOffice\PhpWord\Element\Text $element Type hint */
$element = $this->element;
- $style = '';
+
+ $attributeStyle = $attributeLang = '';
+ $lang = null;
+
$fontStyle = $element->getFontStyle();
- $fStyleIsObject = ($fontStyle instanceof Font);
- if ($fStyleIsObject) {
+ if ($fontStyle instanceof Font) {
+ // Attribute style
$styleWriter = new FontStyleWriter($fontStyle);
- $style = $styleWriter->write();
- } elseif (is_string($fontStyle)) {
- $style = $fontStyle;
+ $fontCSS = $styleWriter->write();
+ if ($fontCSS) {
+ $attributeStyle = ' style="' . $fontCSS . '"';
+ }
+ // Attribute Lang
+ $lang = $fontStyle->getLang();
+ } elseif (!empty($fontStyle)) {
+ // 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 ($style) {
- $attribute = $fStyleIsObject ? 'style' : 'class';
- $this->openingTags = "";
+
+ if ($lang) {
+ $attributeLang = $lang->getLatin();
+ if (!$attributeLang) {
+ $attributeLang = $lang->getEastAsia();
+ }
+ if (!$attributeLang) {
+ $attributeLang = $lang->getBidirectional();
+ }
+ if ($attributeLang) {
+ $attributeLang = " lang='$attributeLang'";
+ }
+ }
+
+ if ($attributeStyle || $attributeLang) {
+ $this->openingTags = "";
$this->closingTags = ' ';
}
}
diff --git a/src/PhpWord/Writer/HTML/Element/TextBreak.php b/src/PhpWord/Writer/HTML/Element/TextBreak.php
index 6ff092dbf7..576f6a8364 100644
--- a/src/PhpWord/Writer/HTML/Element/TextBreak.php
+++ b/src/PhpWord/Writer/HTML/Element/TextBreak.php
@@ -1,4 +1,5 @@
element->getText();
if (is_string($text)) {
- if (Settings::isOutputEscapingEnabled()) {
- $text = $this->escaper->escapeHtml($text);
- }
- } elseif ($text instanceof \PhpOffice\PhpWord\Element\AbstractContainer) {
+ $text = $this->parentWriter->escapeHTML($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 2d86f399b0..61bf20b29a 100644
--- a/src/PhpWord/Writer/HTML/Part/AbstractPart.php
+++ b/src/PhpWord/Writer/HTML/Part/AbstractPart.php
@@ -1,4 +1,5 @@
escaper = new Escaper();
- }
-
/**
* @return string
*/
abstract public function write();
- /**
- * @param \PhpOffice\PhpWord\Writer\AbstractWriter $writer
- */
- public function setParentWriter(AbstractWriter $writer = null)
+ public function setParentWriter(?HTML $writer = null): void
{
$this->parentWriter = $writer;
}
/**
- * @throws \PhpOffice\PhpWord\Exception\Exception
- *
- * @return \PhpOffice\PhpWord\Writer\AbstractWriter
+ * @return HTML
*/
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..bad1415c21 100644
--- a/src/PhpWord/Writer/HTML/Part/Body.php
+++ b/src/PhpWord/Writer/HTML/Part/Body.php
@@ -1,4 +1,5 @@
' . PHP_EOL;
$sections = $phpWord->getSections();
+ $secno = 0;
+ $isTCPDFWriter = $this->getParentWriter() instanceof TCPDF;
foreach ($sections as $section) {
+ ++$secno;
+ if ($isTCPDFWriter && $secno > 1) {
+ $content .= "" . PHP_EOL;
+ } else {
+ $content .= "
" . PHP_EOL;
+ }
$writer = new Container($this->getParentWriter(), $section);
$content .= $writer->write();
+ $content .= '
' . PHP_EOL;
}
$content .= $this->writeNotes();
@@ -52,7 +63,7 @@ public function write()
}
/**
- * Write footnote/endnote contents as textruns
+ * Write footnote/endnote contents as textruns.
*
* @return string
*/
@@ -68,7 +79,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..79235e1c4a 100644
--- a/src/PhpWord/Writer/HTML/Part/Head.php
+++ b/src/PhpWord/Writer/HTML/Part/Head.php
@@ -1,4 +1,5 @@
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';
@@ -63,8 +67,10 @@ public function write()
$method = 'get' . $key;
if ($docProps->$method() != '') {
$content .= '
' . PHP_EOL;
+ . ' content="'
+ . $this->getParentWriter()->escapeHTML($docProps->$method())
+ . '"'
+ . ' />' . PHP_EOL;
}
}
$content .= $this->writeStyles();
@@ -74,40 +80,48 @@ public function write()
}
/**
- * Get styles
- *
- * @return string
+ * Get styles.
*/
- 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/AbstractStyle.php b/src/PhpWord/Writer/HTML/Style/AbstractStyle.php
index cfb54cb8d7..4672347ba2 100644
--- a/src/PhpWord/Writer/HTML/Style/AbstractStyle.php
+++ b/src/PhpWord/Writer/HTML/Style/AbstractStyle.php
@@ -1,4 +1,5 @@
parentWriter = $writer;
}
/**
- * Get parent writer
+ * Get parent writer.
*
- * @return \PhpOffice\PhpWord\Writer\AbstractWriter
+ * @return HTML
*/
public function getParentWriter()
{
@@ -76,13 +80,13 @@ public function getParentWriter()
}
/**
- * Get style
+ * Get style.
*
- * @return array|\PhpOffice\PhpWord\Style\AbstractStyle $style
+ * @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 '';
}
@@ -90,14 +94,15 @@ public function getStyle()
}
/**
- * Takes array where of CSS properties / values and converts to CSS string
+ * Takes array where of CSS properties / values and converts to CSS string.
*
* @param array $css
+ *
* @return string
*/
protected function assembleCss($css)
{
- $pairs = array();
+ $pairs = [];
$string = '';
foreach ($css as $key => $value) {
if ($value != '') {
@@ -114,8 +119,9 @@ protected function assembleCss($css)
/**
* Get value if ...
*
- * @param bool|null $condition
+ * @param null|bool $condition
* @param string $value
+ *
* @return string
*/
protected function getValueIf($condition, $value)
diff --git a/src/PhpWord/Writer/HTML/Style/Font.php b/src/PhpWord/Writer/HTML/Style/Font.php
index 75c98b9bdc..1001b64d2e 100644
--- a/src/PhpWord/Writer/HTML/Style/Font.php
+++ b/src/PhpWord/Writer/HTML/Style/Font.php
@@ -1,4 +1,5 @@
getName();
+ $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($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 +62,35 @@ 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->getWhiteSpace();
+ if ($whitespace) {
+ $css['white-space'] = $whitespace;
+ }
$spacing = $style->getSpacing();
- $css['letter-spacing'] = $this->getValueIf(!is_null($spacing), ($spacing / 20) . 'pt');
+ $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.
+ */
+ 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/Generic.php b/src/PhpWord/Writer/HTML/Style/Generic.php
index ee5d089607..21603a7be1 100644
--- a/src/PhpWord/Writer/HTML/Style/Generic.php
+++ b/src/PhpWord/Writer/HTML/Style/Generic.php
@@ -1,4 +1,5 @@
getStyle();
- $css = array();
+ $css = [];
if (is_array($style) && !empty($style)) {
$css = $style;
diff --git a/src/PhpWord/Writer/HTML/Style/Image.php b/src/PhpWord/Writer/HTML/Style/Image.php
index 93747b4645..30fb373018 100644
--- a/src/PhpWord/Writer/HTML/Style/Image.php
+++ b/src/PhpWord/Writer/HTML/Style/Image.php
@@ -1,4 +1,5 @@
getWidth();
$height = $style->getHeight();
diff --git a/src/PhpWord/Writer/HTML/Style/Paragraph.php b/src/PhpWord/Writer/HTML/Style/Paragraph.php
index 863ef93b14..22267e7b18 100644
--- a/src/PhpWord/Writer/HTML/Style/Paragraph.php
+++ b/src/PhpWord/Writer/HTML/Style/Paragraph.php
@@ -1,4 +1,5 @@
getAlignment()) {
@@ -46,22 +49,33 @@ public function write()
switch ($style->getAlignment()) {
case Jc::CENTER:
$textAlign = 'center';
+
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:
$textAlign = 'right';
+
break;
case Jc::BOTH:
case Jc::DISTRIBUTE:
case Jc::THAI_DISTRIBUTE:
case Jc::JUSTIFY:
$textAlign = 'justify';
+
break;
- default: //all others, align left
+ case Jc::LEFT:
$textAlign = 'left';
+
+ break;
+ default: //all others, including Jc::START
+ $textAlign = $style->isBidi() ? 'right' : 'left';
+
break;
}
@@ -70,14 +84,37 @@ public function write()
// Spacing
$spacing = $style->getSpace();
- if (!is_null($spacing)) {
+ if (null !== $spacing) {
$before = $spacing->getBefore();
$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';
+ $css['margin-top'] = $this->getValueIf(null !== $before, ($before / 20) . 'pt');
+ $css['margin-bottom'] = $this->getValueIf(null !== $after, ($after / 20) . 'pt');
+ }
+
+ // Line Height
+ $lineHeight = $style->getLineHeight();
+ if (!empty($lineHeight)) {
+ $css['line-height'] = $lineHeight;
+ }
+
+ // 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';
}
return $this->assembleCss($css);
diff --git a/src/PhpWord/Writer/HTML/Style/Table.php b/src/PhpWord/Writer/HTML/Style/Table.php
new file mode 100644
index 0000000000..6d3e43e812
--- /dev/null
+++ b/src/PhpWord/Writer/HTML/Style/Table.php
@@ -0,0 +1,86 @@
+getStyle();
+ if (!$style instanceof StyleTable && !$style instanceof StyleCell) {
+ return '';
+ }
+
+ $css = [];
+ 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 (method_exists($style, 'isBidiVisual')) {
+ if ($style->isBidiVisual()) {
+ $css['direction'] = 'rtl';
+ }
+ }
+ if (method_exists($style, 'getVAlign')) {
+ $css['vertical-align'] = $style->getVAlign();
+ }
+
+ 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.php b/src/PhpWord/Writer/ODText.php
index efd0d6a923..c9a524e882 100644
--- a/src/PhpWord/Writer/ODText.php
+++ b/src/PhpWord/Writer/ODText.php
@@ -1,4 +1,5 @@
setPhpWord($phpWord);
// Create parts
- $this->parts = array(
- 'Mimetype' => 'mimetype',
- 'Content' => 'content.xml',
- 'Meta' => 'meta.xml',
- 'Styles' => 'styles.xml',
- 'Manifest' => 'META-INF/manifest.xml',
- );
+ $this->parts = [
+ 'Mimetype' => 'mimetype',
+ 'Content' => 'content.xml',
+ 'Meta' => 'meta.xml',
+ 'Styles' => 'styles.xml',
+ 'Manifest' => 'META-INF/manifest.xml',
+ ];
foreach (array_keys($this->parts) as $partName) {
- $partClass = get_class($this) . '\\Part\\' . $partName;
+ $partClass = static::class . '\\Part\\' . $partName;
if (class_exists($partClass)) {
- /** @var $partObject \PhpOffice\PhpWord\Writer\ODText\Part\AbstractPart Type hint */
+ /** @var AbstractPart $partObject Type hint */
$partObject = new $partClass();
$partObject->setParentWriter($this);
$this->writerParts[strtolower($partName)] = $partObject;
@@ -56,15 +64,13 @@ public function __construct(PhpWord $phpWord = null)
}
// Set package paths
- $this->mediaPaths = array('image' => 'Pictures/');
+ $this->mediaPaths = ['image' => 'Pictures/'];
}
/**
* Save PhpWord to file.
- *
- * @param string $filename
*/
- public function save($filename = null)
+ public function save(string $filename): void
{
$filename = $this->getTempFile($filename);
$zip = $this->getZipArchive($filename);
@@ -77,8 +83,28 @@ public function save($filename = null)
// 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/AbstractElement.php b/src/PhpWord/Writer/ODText/Element/AbstractElement.php
index 9c9fc1c477..97d1875cd1 100644
--- a/src/PhpWord/Writer/ODText/Element/AbstractElement.php
+++ b/src/PhpWord/Writer/ODText/Element/AbstractElement.php
@@ -1,4 +1,5 @@
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/Container.php b/src/PhpWord/Writer/ODText/Element/Container.php
index 6ba8124f0f..6b0fee8c64 100644
--- a/src/PhpWord/Writer/ODText/Element/Container.php
+++ b/src/PhpWord/Writer/ODText/Element/Container.php
@@ -1,4 +1,5 @@
+ */
+ protected $containerWithoutP = ['TextRun', 'Footnote', 'Endnote'];
}
diff --git a/src/PhpWord/Writer/ODText/Element/Field.php b/src/PhpWord/Writer/ODText/Element/Field.php
new file mode 100644
index 0000000000..2f81eb3f3d
--- /dev/null
+++ b/src/PhpWord/Writer/ODText/Element/Field.php
@@ -0,0 +1,99 @@
+getElement();
+ if (!$element instanceof \PhpOffice\PhpWord\Element\Field) {
+ return;
+ }
+
+ $type = strtolower($element->getType());
+ switch ($type) {
+ case 'date':
+ case 'page':
+ case 'numpages':
+ case 'filename':
+ $this->writeDefault($element, $type);
+
+ break;
+ }
+ }
+
+ private function writeDefault(\PhpOffice\PhpWord\Element\Field $element, $type): void
+ {
+ $xmlWriter = $this->getXmlWriter();
+
+ $xmlWriter->startElement('text:span');
+
+ $fstyle = $element->getFontStyle();
+ if (is_string($fstyle)) {
+ $xmlWriter->writeAttribute('text:style-name', $fstyle);
+ }
+
+ switch ($type) {
+ case 'date':
+ $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;
+ 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/ODText/Element/Formula.php b/src/PhpWord/Writer/ODText/Element/Formula.php
new file mode 100644
index 0000000000..2c7ce3aaf1
--- /dev/null
+++ b/src/PhpWord/Writer/ODText/Element/Formula.php
@@ -0,0 +1,75 @@
+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/Element/Image.php b/src/PhpWord/Writer/ODText/Element/Image.php
index add45e1044..baa3c8cdb6 100644
--- a/src/PhpWord/Writer/ODText/Element/Image.php
+++ b/src/PhpWord/Writer/ODText/Element/Image.php
@@ -1,4 +1,5 @@
getXmlWriter();
$element = $this->getElement();
- if (!$element instanceof \PhpOffice\PhpWord\Element\Image) {
+ if (!$element instanceof ElementImage) {
return;
}
@@ -43,11 +44,16 @@ public function write()
$width = Converter::pixelToCm($style->getWidth());
$height = Converter::pixelToCm($style->getHeight());
- $xmlWriter->startElement('text:p');
- $xmlWriter->writeAttribute('text:style-name', 'Standard');
+ $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 +69,8 @@ public function write()
$xmlWriter->endElement(); // draw:frame
- $xmlWriter->endElement(); // text:p
+ if (!$this->withoutP) {
+ $xmlWriter->endElement(); // text:p
+ }
}
}
diff --git a/src/PhpWord/Writer/ODText/Element/Link.php b/src/PhpWord/Writer/ODText/Element/Link.php
index d6fec50777..9ef35692c8 100644
--- a/src/PhpWord/Writer/ODText/Element/Link.php
+++ b/src/PhpWord/Writer/ODText/Element/Link.php
@@ -1,4 +1,5 @@
getXmlWriter();
$element = $this->getElement();
@@ -41,7 +42,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/ListItemRun.php b/src/PhpWord/Writer/ODText/Element/ListItemRun.php
new file mode 100644
index 0000000000..1319e48577
--- /dev/null
+++ b/src/PhpWord/Writer/ODText/Element/ListItemRun.php
@@ -0,0 +1,57 @@
+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/PageBreak.php b/src/PhpWord/Writer/ODText/Element/PageBreak.php
index ecf4760740..ca9e53f4a6 100644
--- a/src/PhpWord/Writer/ODText/Element/PageBreak.php
+++ b/src/PhpWord/Writer/ODText/Element/PageBreak.php
@@ -1,4 +1,5 @@
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/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 @@
+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/Table.php b/src/PhpWord/Writer/ODText/Element/Table.php
index 088330ae5f..097f6742bb 100644
--- a/src/PhpWord/Writer/ODText/Element/Table.php
+++ b/src/PhpWord/Writer/ODText/Element/Table.php
@@ -1,4 +1,5 @@
getXmlWriter();
$element = $this->getElement();
- if (!$element instanceof \PhpOffice\PhpWord\Element\Table) {
+ if (!$element instanceof TableElement) {
return;
}
$rows = $element->getRows();
@@ -44,7 +45,7 @@ public function write()
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);
@@ -59,15 +60,12 @@ public function write()
/**
* Write column.
- *
- * @param \PhpOffice\Common\XMLWriter $xmlWriter
- * @param \PhpOffice\PhpWord\Element\Table $element
*/
- private function writeColumns(XMLWriter $xmlWriter, TableElement $element)
+ private function writeColumns(XMLWriter $xmlWriter, TableElement $element): void
{
$colCount = $element->countColumns();
- for ($i = 0; $i < $colCount; $i++) {
+ for ($i = 0; $i < $colCount; ++$i) {
$xmlWriter->startElement('table:table-column');
$xmlWriter->writeAttribute('table:style-name', $element->getElementId() . '.' . $i);
$xmlWriter->endElement();
@@ -76,14 +74,11 @@ private function writeColumns(XMLWriter $xmlWriter, TableElement $element)
/**
* Write row.
- *
- * @param \PhpOffice\Common\XMLWriter $xmlWriter
- * @param \PhpOffice\PhpWord\Element\Row $row
*/
- private function writeRow(XMLWriter $xmlWriter, RowElement $row)
+ private function writeRow(XMLWriter $xmlWriter, RowElement $row): void
{
$xmlWriter->startElement('table:table-row');
- /** @var $row \PhpOffice\PhpWord\Element\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 7dcd28a013..3996972387 100644
--- a/src/PhpWord/Writer/ODText/Element/Text.php
+++ b/src/PhpWord/Writer/ODText/Element/Text.php
@@ -1,4 +1,5 @@
getXmlWriter();
$element = $this->getElement();
@@ -42,12 +43,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
@@ -57,29 +58,29 @@ public function write()
$xmlWriter->writeAttribute('text:change-id', $element->getTrackChange()->getElementId());
$xmlWriter->endElement();
} else {
- if (empty($fontStyle)) {
- if (empty($paragraphStyle)) {
- $xmlWriter->writeAttribute('text:style-name', 'P1');
- } elseif (is_string($paragraphStyle)) {
- $xmlWriter->writeAttribute('text:style-name', $paragraphStyle);
+ if (empty($paragraphStyle)) {
+ if (!$this->withoutP) {
+ $xmlWriter->writeAttribute('text:style-name', 'Normal');
}
- $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)) {
+ } 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->writeText($element->getText());
- $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();
}
}
@@ -88,7 +89,7 @@ public function write()
}
}
- private function writeChangeInsertion($start = true, TrackChange $trackChange = null)
+ private function writeChangeInsertion($start = true, ?TrackChange $trackChange = null): void
{
if ($trackChange == null || $trackChange->getChangeType() != TrackChange::INSERTED) {
return;
diff --git a/src/PhpWord/Writer/ODText/Element/TextBreak.php b/src/PhpWord/Writer/ODText/Element/TextBreak.php
index 80cd13870a..1a69700792 100644
--- a/src/PhpWord/Writer/ODText/Element/TextBreak.php
+++ b/src/PhpWord/Writer/ODText/Element/TextBreak.php
@@ -1,4 +1,5 @@
getXmlWriter();
diff --git a/src/PhpWord/Writer/ODText/Element/TextRun.php b/src/PhpWord/Writer/ODText/Element/TextRun.php
index 78e5a8adae..9d009c3994 100644
--- a/src/PhpWord/Writer/ODText/Element/TextRun.php
+++ b/src/PhpWord/Writer/ODText/Element/TextRun.php
@@ -1,4 +1,5 @@
getXmlWriter();
$element = $this->getElement();
$xmlWriter->startElement('text:p');
+ /** @scrutinizer ignore-call */
+ $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..6108710517 100644
--- a/src/PhpWord/Writer/ODText/Element/Title.php
+++ b/src/PhpWord/Writer/ODText/Element/Title.php
@@ -1,4 +1,5 @@
getXmlWriter();
$element = $this->getElement();
@@ -36,14 +37,44 @@ 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) {
+ if (self::compareToFirstElement($element, $sect->getElements())) {
+ $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);
- } elseif ($text instanceof \PhpOffice\PhpWord\Element\AbstractContainer) {
+ }
+ if ($text instanceof \PhpOffice\PhpWord\Element\AbstractContainer) {
$containerWriter = new Container($xmlWriter, $text);
$containerWriter->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/AbstractPart.php b/src/PhpWord/Writer/ODText/Part/AbstractPart.php
index f2844de6f0..458831d3ad 100644
--- a/src/PhpWord/Writer/ODText/Part/AbstractPart.php
+++ b/src/PhpWord/Writer/ODText/Part/AbstractPart.php
@@ -1,4 +1,5 @@
writeAttribute('office:version', '1.2');
$xmlWriter->writeAttribute('xmlns:office', 'urn:oasis:names:tc:opendocument:xmlns:office:1.0');
@@ -71,20 +76,18 @@ protected function writeCommonRootAttributes(XMLWriter $xmlWriter)
/**
* Write font faces declaration.
- *
- * @param \PhpOffice\Common\XMLWriter $xmlWriter
*/
- protected function writeFontFaces(XMLWriter $xmlWriter)
+ protected function writeFontFaces(XMLWriter $xmlWriter): void
{
$xmlWriter->startElement('office:font-face-decls');
- $fontTable = array();
+ $fontTable = [];
$styles = Style::getStyles();
$numFonts = 0;
if (count($styles) > 0) {
foreach ($styles as $style) {
// Font
if ($style instanceof Font) {
- $numFonts++;
+ ++$numFonts;
$name = $style->getName();
if (!in_array($name, $fontTable)) {
$fontTable[] = $name;
@@ -106,4 +109,29 @@ protected function writeFontFaces(XMLWriter $xmlWriter)
}
$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 99ee93536e..b4958e84e6 100644
--- a/src/PhpWord/Writer/ODText/Part/Content.php
+++ b/src/PhpWord/Writer/ODText/Part/Content.php
@@ -1,4 +1,5 @@
array(), 'Image' => array(), 'Table' => array());
+ private $autoStyles = ['Section' => [], 'Image' => [], 'Table' => []];
+
+ private $imageParagraphStyles = [];
/**
- * Write part
+ * Write part.
*
* @return string
*/
@@ -77,7 +82,7 @@ public function write()
$xmlWriter->startElement('office:text');
// Tracked changes declarations
- $trackedChanges = array();
+ $trackedChanges = [];
$sections = $phpWord->getSections();
foreach ($sections as $section) {
$this->collectTrackedChanges($section, $trackedChanges);
@@ -101,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());
}
@@ -111,7 +117,7 @@ public function write()
$xmlWriter->endElement(); // text:tracked-changes
// Sequence declarations
- $sequences = array('Illustration', 'Table', 'Text', 'Drawing');
+ $sequences = ['Illustration', 'Table', 'Text', 'Drawing'];
$xmlWriter->startElement('text:sequence-decls');
foreach ($sequences as $sequence) {
$xmlWriter->startElement('text:sequence-decl');
@@ -128,8 +134,14 @@ 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->setPart($this);
$containerWriter->write();
+
$xmlWriter->endElement(); // text:section
}
@@ -145,10 +157,8 @@ public function write()
* Write automatic styles other than fonts and paragraphs.
*
* @since 0.11.0
- *
- * @param \PhpOffice\Common\XMLWriter $xmlWriter
*/
- private function writeAutoStyles(XMLWriter $xmlWriter)
+ private function writeAutoStyles(XMLWriter $xmlWriter): void
{
$xmlWriter->startElement('office:automatic-styles');
@@ -167,43 +177,70 @@ private function writeAutoStyles(XMLWriter $xmlWriter)
/**
* Write automatic styles.
- *
- * @param \PhpOffice\Common\XMLWriter $xmlWriter
*/
- private function writeTextStyles(XMLWriter $xmlWriter)
+ private function writeTextStyles(XMLWriter $xmlWriter): void
{
$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();
+ $countsects = count($sects);
+ for ($i = 0; $i < $countsects; ++$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 = (string) $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 ParagraphStyleWriter($xmlWriter, $style);
+ $styleWriter->write();
+ }
}
/**
* Get automatic styles.
- *
- * @param \PhpOffice\PhpWord\PhpWord $phpWord
*/
- private function getAutoStyles(PhpWord $phpWord)
+ private function getAutoStyles(PhpWord $phpWord): void
{
$sections = $phpWord->getSections();
$paragraphStyleCount = 0;
@@ -217,34 +254,43 @@ private function getAutoStyles(PhpWord $phpWord)
}
/**
- * Get all styles of each elements in container recursively
+ * Get all styles of each elements in container recursively.
*
* 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
+ *
* @todo Simplify the logic
*/
- private function getContainerStyle($container, &$paragraphStyleCount, &$fontStyleCount)
+ private function getContainerStyle($container, &$paragraphStyleCount, &$fontStyleCount): void
{
$elements = $container->getElements();
foreach ($elements as $element) {
if ($element instanceof TextRun) {
+ $this->getElementStyleTextRun($element, $paragraphStyleCount);
$this->getContainerStyle($element, $paragraphStyleCount, $fontStyleCount);
} elseif ($element instanceof Text) {
$this->getElementStyle($element, $paragraphStyleCount, $fontStyleCount);
+ } elseif ($element instanceof Field) {
+ $this->getElementStyleField($element, $fontStyleCount);
} elseif ($element instanceof Image) {
$style = $element->getStyle();
$style->setStyleName('fr' . $element->getMediaIndex());
$this->autoStyles['Image'][] = $style;
+ $sty = new 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());
@@ -254,13 +300,13 @@ private function getContainerStyle($container, &$paragraphStyleCount, &$fontStyl
}
/**
- * Get style of individual element
+ * Get style of individual element.
*
- * @param \PhpOffice\PhpWord\Element\Text $element
+ * @param Text $element
* @param int $paragraphStyleCount
* @param int $fontStyleCount
*/
- private function getElementStyle(&$element, &$paragraphStyleCount, &$fontStyleCount)
+ private function getElementStyle($element, &$paragraphStyleCount, &$fontStyleCount): void
{
$fontStyle = $element->getFontStyle();
$paragraphStyle = $element->getParagraphStyle();
@@ -268,33 +314,106 @@ private function getElementStyle(&$element, &$paragraphStyleCount, &$fontStyleCo
if ($fontStyle instanceof Font) {
// Font
- $fontStyleCount++;
- $style = $phpWord->addFontStyle("T{$fontStyleCount}", $fontStyle);
+ $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 ($paragraphStyle) {
+ ++$paragraphStyleCount;
+ $parstylename = "P$paragraphStyleCount" . "_$paragraphStyle";
+ $style = $phpWord->addParagraphStyle($parstylename, $paragraphStyle);
$style->setAuto();
- $element->setFontStyle("T{$fontStyleCount}");
- } elseif ($paragraphStyle instanceof Paragraph) {
+ $element->setParagraphStyle($parstylename);
+ }
+ }
+
+ /**
+ * Get font style of individual field element.
+ *
+ * @param Field $element
+ * @param int $fontStyleCount
+ */
+ private function getElementStyleField($element, &$fontStyleCount): void
+ {
+ $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.
+ *
+ * @param TextRun $element
+ * @param int $paragraphStyleCount
+ */
+ private function getElementStyleTextRun($element, &$paragraphStyleCount): void
+ {
+ $paragraphStyle = $element->getParagraphStyle();
+ $phpWord = $this->getParentWriter()->getPhpWord();
+
+ if ($paragraphStyle instanceof Paragraph) {
// Paragraph
- $paragraphStyleCount++;
- $style = $phpWord->addParagraphStyle("P{$paragraphStyleCount}", array());
+ $name = $paragraphStyle->getStyleName();
+ if (!$name) {
+ ++$paragraphStyleCount;
+ $style = $phpWord->addParagraphStyle("P{$paragraphStyleCount}", $paragraphStyle);
+ $style->setAuto();
+ $element->setParagraphStyle("P{$paragraphStyleCount}");
+ } else {
+ $element->setParagraphStyle($name);
+ }
+ } elseif ($paragraphStyle) {
+ ++$paragraphStyleCount;
+ $parstylename = "P$paragraphStyleCount" . "_$paragraphStyle";
+ $style = $phpWord->addParagraphStyle($parstylename, $paragraphStyle);
$style->setAuto();
- $element->setParagraphStyle("P{$paragraphStyleCount}");
+ $element->setParagraphStyle($parstylename);
}
}
/**
- * Finds all tracked changes
+ * Finds all tracked changes.
*
- * @param AbstractContainer $container
* @param \PhpOffice\PhpWord\Element\AbstractElement[] $trackedChanges
*/
- private function collectTrackedChanges(AbstractContainer $container, &$trackedChanges = array())
+ private function collectTrackedChanges(AbstractContainer $container, &$trackedChanges = []): void
{
$elements = $container->getElements();
foreach ($elements as $element) {
if ($element->getTrackChange() != null) {
$trackedChanges[] = $element;
}
- if (is_callable(array($element, 'getElements'))) {
+ if (is_callable([$element, 'getElements'])) {
$this->collectTrackedChanges($element, $trackedChanges);
}
}
diff --git a/src/PhpWord/Writer/ODText/Part/Manifest.php b/src/PhpWord/Writer/ODText/Part/Manifest.php
index f952b4c072..200da15836 100644
--- a/src/PhpWord/Writer/ODText/Part/Manifest.php
+++ b/src/PhpWord/Writer/ODText/Part/Manifest.php
@@ -1,4 +1,5 @@
getXmlWriter();
$xmlWriter->startDocument('1.0', 'UTF-8');
@@ -46,7 +48,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 +66,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/ODText/Part/Meta.php b/src/PhpWord/Writer/ODText/Part/Meta.php
index f38ad01d56..21410ba9fd 100644
--- a/src/PhpWord/Writer/ODText/Part/Meta.php
+++ b/src/PhpWord/Writer/ODText/Part/Meta.php
@@ -1,4 +1,5 @@
writeElement('meta:keyword', $docProps->getKeywords());
// Category, company, and manager are put in meta namespace
- $properties = array('Category', 'Company', 'Manager');
+ $properties = ['Category', 'Company', 'Manager'];
foreach ($properties as $property) {
$method = "get{$property}";
if ($docProps->$method() !== null) {
@@ -84,15 +85,14 @@ public function write()
}
/**
- * Write individual property
+ * Write individual property.
*
- * @param \PhpOffice\Common\XMLWriter $xmlWriter
* @param string $property
* @param string $value
*
* @todo Handle other `$type`: double|date|dateTime|duration|boolean (4th arguments)
*/
- private function writeCustomProperty(XMLWriter $xmlWriter, $property, $value)
+ private function writeCustomProperty(XMLWriter $xmlWriter, $property, $value): void
{
$xmlWriter->startElement('meta:user-defined');
$xmlWriter->writeAttribute('meta:name', $property);
diff --git a/src/PhpWord/Writer/ODText/Part/Mimetype.php b/src/PhpWord/Writer/ODText/Part/Mimetype.php
index 552f54403a..1b94c155b1 100644
--- a/src/PhpWord/Writer/ODText/Part/Mimetype.php
+++ b/src/PhpWord/Writer/ODText/Part/Mimetype.php
@@ -1,4 +1,5 @@
startElement('style:default-style');
$xmlWriter->writeAttribute('style:family', 'paragraph');
@@ -83,17 +83,21 @@ private function writeDefault(XMLWriter $xmlWriter)
$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');
+ $latinLang = $language != null && is_string($language->getLatin()) ? explode('-', $language->getLatin()) : ['fr', 'FR'];
+ $asianLang = $language != null && is_string($language->getEastAsia()) ? explode('-', $language->getEastAsia()) : ['zh', 'CN'];
+ $complexLang = $language != null && is_string($language->getBidirectional()) ? explode('-', $language->getBidirectional()) : ['hi', 'IN'];
+ if ($this->getParentWriter()->getPhpWord()->getSettings()->hasHideGrammaticalErrors()) {
+ $latinLang = $asianLang = $complexLang = ['zxx', 'none'];
+ }
// 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');
@@ -113,10 +117,8 @@ private function writeDefault(XMLWriter $xmlWriter)
/**
* Write named styles.
- *
- * @param \PhpOffice\Common\XMLWriter $xmlWriter
*/
- private function writeNamed(XMLWriter $xmlWriter)
+ private function writeNamed(XMLWriter $xmlWriter): void
{
$styles = Style::getStyles();
if (count($styles) > 0) {
@@ -124,7 +126,7 @@ private function writeNamed(XMLWriter $xmlWriter)
if ($style->isAuto() === false) {
$styleClass = str_replace('\\Style\\', '\\Writer\\ODText\\Style\\', get_class($style));
if (class_exists($styleClass)) {
- /** @var $styleWriter \PhpOffice\PhpWord\Writer\ODText\Style\AbstractStyle Type hint */
+ /** @var \PhpOffice\PhpWord\Writer\ODText\Style\AbstractStyle $styleWriter Type hint */
$styleWriter = new $styleClass($xmlWriter, $style);
$styleWriter->write();
}
@@ -133,25 +135,72 @@ private function writeNamed(XMLWriter $xmlWriter)
}
}
+ /**
+ * Convert int in twips to inches/cm then to string and append unit.
+ *
+ * @param float|int $twips
+ * @param float $factor
+ * return string
+ */
+ private static function cvttwiptostr($twips, $factor = 1.0)
+ {
+ $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.
+ */
+ private function writePageLayout(XMLWriter $xmlWriter): void
+ {
+ $sections = $this->getParentWriter()->getPhpWord()->getSections();
+ $countsects = count($sections);
+ for ($i = 0; $i < $countsects; ++$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): void
{
+ $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;
+ }
+ $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', '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 +225,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) {
+ $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
@@ -186,18 +249,51 @@ private function writePageLayout(XMLWriter $xmlWriter)
/**
* Write master style.
- *
- * @param \PhpOffice\Common\XMLWriter $xmlWriter
*/
- private function writeMaster(XMLWriter $xmlWriter)
+ private function writeMaster(XMLWriter $xmlWriter): void
{
$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();
+ $countsects = count($sections);
+ for ($i = 0; $i < $countsects; ++$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/AbstractStyle.php b/src/PhpWord/Writer/ODText/Style/AbstractStyle.php
index f7679ab22c..3545009f6b 100644
--- a/src/PhpWord/Writer/ODText/Style/AbstractStyle.php
+++ b/src/PhpWord/Writer/ODText/Style/AbstractStyle.php
@@ -1,4 +1,5 @@
getStyle();
if (!$style instanceof \PhpOffice\PhpWord\Style\Font) {
@@ -35,6 +36,14 @@ public function write()
}
$xmlWriter = $this->getXmlWriter();
+ $stylep = $style->getParagraph();
+ if ($stylep instanceof \PhpOffice\PhpWord\Style\Paragraph) {
+ $temp1 = clone $stylep;
+ $temp1->setStyleName($style->getStyleName());
+ $temp2 = new Paragraph($xmlWriter, $temp1);
+ $temp2->write();
+ }
+
$xmlWriter->startElement('style:style');
$xmlWriter->writeAttribute('style:name', $style->getStyleName());
$xmlWriter->writeAttribute('style:family', 'text');
@@ -53,7 +62,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 +91,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/Image.php b/src/PhpWord/Writer/ODText/Style/Image.php
index 13005a7f03..56c4f57a5b 100644
--- a/src/PhpWord/Writer/ODText/Style/Image.php
+++ b/src/PhpWord/Writer/ODText/Style/Image.php
@@ -1,4 +1,5 @@
getStyle();
diff --git a/src/PhpWord/Writer/ODText/Style/Numbering.php b/src/PhpWord/Writer/ODText/Style/Numbering.php
new file mode 100644
index 0000000000..287b25b34a
--- /dev/null
+++ b/src/PhpWord/Writer/ODText/Style/Numbering.php
@@ -0,0 +1,87 @@
+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/ODText/Style/Paragraph.php b/src/PhpWord/Writer/ODText/Style/Paragraph.php
index f247dcc11c..ca22a0934c 100644
--- a/src/PhpWord/Writer/ODText/Style/Paragraph.php
+++ b/src/PhpWord/Writer/ODText/Style/Paragraph.php
@@ -1,4 +1,5 @@
Jc::LEFT,
+ Jc::START => Jc::RIGHT,
+ ];
+
+ private const NON_BIDI_MAP = [
+ Jc::START => Jc::LEFT,
+ Jc::END => Jc::RIGHT,
+ ];
+
/**
* Write style.
*/
- public function write()
+ public function write(): void
{
$style = $this->getStyle();
- if (!$style instanceof \PhpOffice\PhpWord\Style\Paragraph) {
+ if (!$style instanceof Style\Paragraph) {
return;
}
$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 = (string) $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();
+ $pagestart = $psn;
+ } elseif (substr($styleName, 0, 2) === 'HD') {
+ $styleAuto = true;
+ $psm = 'Heading_' . substr($styleName, 2);
+ $stylep = Style::getStyle($psm);
+ if ($stylep instanceof Style\Font) {
+ $stylep = $stylep->getParagraph();
+ }
+ if ($stylep instanceof 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');
+ }
+ $alignment = $style->getAlignment();
+ $bidi = $style->isBidi();
+ $defaultRtl = Settings::isDefaultRtl();
+ 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');
+
+ $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) {
+ if (!empty($indent)) {
+ $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/src/PhpWord/Writer/ODText/Style/Section.php b/src/PhpWord/Writer/ODText/Style/Section.php
index 92d8891170..05152a3944 100644
--- a/src/PhpWord/Writer/ODText/Style/Section.php
+++ b/src/PhpWord/Writer/ODText/Style/Section.php
@@ -1,4 +1,5 @@
getStyle();
diff --git a/src/PhpWord/Writer/ODText/Style/Table.php b/src/PhpWord/Writer/ODText/Style/Table.php
index 646f2e44ca..b30389d8e8 100644
--- a/src/PhpWord/Writer/ODText/Style/Table.php
+++ b/src/PhpWord/Writer/ODText/Style/Table.php
@@ -1,4 +1,5 @@
getStyle();
@@ -50,7 +51,7 @@ public function write()
$cellWidths = $style->getColumnWidths();
$countCellWidths = $cellWidths === null ? 0 : count($cellWidths);
- for ($i = 0; $i < $countCellWidths; $i++) {
+ for ($i = 0; $i < $countCellWidths; ++$i) {
$width = $cellWidths[$i];
$xmlWriter->startElement('style:style');
$xmlWriter->writeAttribute('style:name', $style->getStyleName() . '.' . $i);
diff --git a/src/PhpWord/Writer/PDF.php b/src/PhpWord/Writer/PDF.php
index 64dcc7898d..4f7f1be99a 100644
--- a/src/PhpWord/Writer/PDF.php
+++ b/src/PhpWord/Writer/PDF.php
@@ -1,4 +1,5 @@
renderer = new $rendererName($phpWord);
}
@@ -65,6 +63,7 @@ public function __construct(PhpWord $phpWord)
*
* @param string $name Renderer library method name
* @param mixed[] $arguments Array of arguments to pass to the renderer method
+ *
* @return mixed Returned data from the PDF renderer wrapper method
*/
public function __call($name, $arguments)
@@ -74,6 +73,16 @@ public function __call($name, $arguments)
// throw new Exception("PDF Rendering library has not been defined.");
// }
- return call_user_func_array(array($this->renderer, $name), $arguments);
+ return call_user_func_array([$this->getRenderer(), $name], $arguments);
+ }
+
+ public function save(string $filename): void
+ {
+ $this->getRenderer()->save($filename);
+ }
+
+ public function getRenderer(): AbstractRenderer
+ {
+ return $this->renderer;
}
}
diff --git a/src/PhpWord/Writer/PDF/AbstractRenderer.php b/src/PhpWord/Writer/PDF/AbstractRenderer.php
index 5f9e3b3a8c..125bf4fa43 100644
--- a/src/PhpWord/Writer/PDF/AbstractRenderer.php
+++ b/src/PhpWord/Writer/PDF/AbstractRenderer.php
@@ -1,4 +1,5 @@
'A4', // (210 mm by 297 mm)
- );
+ ];
/**
- * Create new instance
+ * Create new instance.
*
* @param PhpWord $phpWord PhpWord object
- *
- * @throws \PhpOffice\PhpWord\Exception\Exception
*/
public function __construct(PhpWord $phpWord)
{
parent::__construct($phpWord);
+ $this->isPdf = true;
if ($this->includeFile != null) {
$includeFile = Settings::getPdfRendererPath() . '/' . $this->includeFile;
if (file_exists($includeFile)) {
@@ -95,10 +95,16 @@ public function __construct(PhpWord $phpWord)
// @codeCoverageIgnoreEnd
}
}
+
+ // Configuration
+ $options = Settings::getPdfRendererOptions();
+ if (!empty($options['font'])) {
+ $this->setFont($options['font']);
+ }
}
/**
- * Get Font
+ * Get Font.
*
* @return string
*/
@@ -112,9 +118,10 @@ public function getFont()
* 'arialunicid0-chinese-simplified'
* 'arialunicid0-chinese-traditional'
* 'arialunicid0-korean'
- * 'arialunicid0-japanese'
+ * 'arialunicid0-japanese'.
*
* @param string $fontName
+ *
* @return self
*/
public function setFont($fontName)
@@ -125,7 +132,7 @@ public function setFont($fontName)
}
/**
- * Get Paper Size
+ * Get Paper Size.
*
* @return int
*/
@@ -135,9 +142,10 @@ public function getPaperSize()
}
/**
- * Set Paper Size
+ * Set Paper Size.
*
* @param int $value Paper size = PAPERSIZE_A4
+ *
* @return self
*/
public function setPaperSize($value = 9)
@@ -148,7 +156,7 @@ public function setPaperSize($value = 9)
}
/**
- * Get Orientation
+ * Get Orientation.
*
* @return string
*/
@@ -158,9 +166,10 @@ public function getOrientation()
}
/**
- * Set Orientation
+ * Set Orientation.
*
* @param string $value Page orientation ORIENTATION_DEFAULT
+ *
* @return self
*/
public function setOrientation($value = 'default')
@@ -171,35 +180,31 @@ public function setOrientation($value = 'default')
}
/**
- * Save PhpWord to PDF file, pre-save
+ * Save PhpWord to PDF file, pre-save.
*
* @param string $filename Name of the file to save as
*
- * @throws \PhpOffice\PhpWord\Exception\Exception
* @return resource
*/
protected function prepareForSave($filename = null)
{
- $fileHandle = fopen($filename, 'w');
+ $fileHandle = fopen($filename, 'wb');
// @codeCoverageIgnoreStart
// Can't find any test case. Uncomment when found.
if ($fileHandle === false) {
throw new Exception("Could not open file $filename for writing.");
}
// @codeCoverageIgnoreEnd
- $this->isPdf = true;
return $fileHandle;
}
/**
- * Save PhpWord to PDF file, post-save
+ * Save PhpWord to PDF file, post-save.
*
* @param resource $fileHandle
- *
- * @throws Exception
*/
- protected function restoreStateAfterSave($fileHandle)
+ protected function restoreStateAfterSave($fileHandle): void
{
fclose($fileHandle);
}
diff --git a/src/PhpWord/Writer/PDF/DomPDF.php b/src/PhpWord/Writer/PDF/DomPDF.php
index 5fa8f75dbb..464dbfa59f 100644
--- a/src/PhpWord/Writer/PDF/DomPDF.php
+++ b/src/PhpWord/Writer/PDF/DomPDF.php
@@ -1,4 +1,5 @@
getFont()) {
+ $options->set('defaultFont', $this->getFont());
+ }
+
+ return new DompdfLib($options);
+ }
+
+ /**
+ * Save PhpWord to file.
*/
- public function save($filename = null)
+ public function save(string $filename): void
{
$fileHandle = parent::prepareForSave($filename);
@@ -49,7 +64,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..03ef1f3ad7 100644
--- a/src/PhpWord/Writer/PDF/MPDF.php
+++ b/src/PhpWord/Writer/PDF/MPDF.php
@@ -1,4 +1,5 @@
';
+ private const BODY_TAG = '';
+
/**
- * Overridden to set the correct includefile, only needed for MPDF 5
+ * Overridden to set the correct includefile, only needed for MPDF 5.
*
* @codeCoverageIgnore
- * @param PhpWord $phpWord
*/
public function __construct(PhpWord $phpWord)
{
@@ -45,11 +48,26 @@ public function __construct(PhpWord $phpWord)
}
/**
- * Save PhpWord to file.
+ * Gets the implementation of external PDF library that should be used.
*
- * @param string $filename Name of the file to save as
+ * @return \Mpdf\Mpdf implementation
*/
- public function save($filename = null)
+ protected function createExternalWriterInstance()
+ {
+ $mPdfClass = $this->getMPdfClassName();
+
+ $options = [];
+ if ($this->getFont()) {
+ $options['default_font'] = $this->getFont();
+ }
+
+ return new $mPdfClass($options);
+ }
+
+ /**
+ * Save PhpWord to file.
+ */
+ public function save(string $filename): void
{
$fileHandle = parent::prepareForSave($filename);
@@ -58,8 +76,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);
@@ -72,7 +89,24 @@ public function save($filename = null)
$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'));
@@ -81,9 +115,10 @@ public function save($filename = null)
}
/**
- * Return classname of MPDF to instantiate
+ * Return classname of MPDF to instantiate.
*
* @codeCoverageIgnore
+ *
* @return string
*/
private function getMPdfClassName()
diff --git a/src/PhpWord/Writer/PDF/TCPDF.php b/src/PhpWord/Writer/PDF/TCPDF.php
index badab0460e..93bdd58528 100644
--- a/src/PhpWord/Writer/PDF/TCPDF.php
+++ b/src/PhpWord/Writer/PDF/TCPDF.php
@@ -1,4 +1,5 @@
getFont()) {
+ $instance->setFont($this->getFont(), $instance->getFontStyle(), $instance->getFontSizePt());
+ }
+
+ 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(TCPDFBase $pdf): void
+ {
+ $pdf->AddPage();
+ $customStyles = Style::getStyles();
+ $normal = $customStyles['Normal'] ?? null;
+ if ($normal instanceof Style\Paragraph) {
+ $before = $normal->getSpaceBefore();
+ $after = $normal->getSpaceAfter();
+ if (is_numeric($before) && is_numeric($after)) {
+ $height = $normal->getLineHeight() ?? '';
+ $pdf->setHtmlVSpace([
+ 'p' => [
+ ['n' => $before, 'h' => $height],
+ ['n' => $after, 'h' => $height],
+ ],
+ ]);
+ }
+ }
+ }
+
+ /**
+ * Save PhpWord to file.
*/
- public function save($filename = null)
+ public function save(string $filename): void
{
$fileHandle = parent::prepareForSave($filename);
// PDF settings
- $paperSize = 'A4';
+ $paperSize = strtoupper(Settings::getDefaultPaper());
$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);
- $pdf->AddPage();
$pdf->SetFont($this->getFont());
+ $this->prepareToWrite($pdf);
$pdf->writeHTML($this->getContent());
// Write document properties
diff --git a/src/PhpWord/Writer/RTF.php b/src/PhpWord/Writer/RTF.php
index 0604e8b56b..390311aa26 100644
--- a/src/PhpWord/Writer/RTF.php
+++ b/src/PhpWord/Writer/RTF.php
@@ -1,4 +1,5 @@
setPhpWord($phpWord);
- $this->parts = array('Header', 'Document');
+ $this->parts = ['Header', 'Document'];
foreach ($this->parts as $partName) {
- $partClass = get_class($this) . '\\Part\\' . $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;
@@ -56,19 +55,17 @@ public function __construct(PhpWord $phpWord = null)
/**
* Save content to file.
- *
- * @param string $filename
- * @throws \PhpOffice\PhpWord\Exception\Exception
*/
- public function save($filename = null)
+ public function save(string $filename): void
{
$this->writeFile($this->openFile($filename), $this->getContent());
}
/**
- * Get content
+ * Get content.
*
* @return string
+ *
* @since 0.11.0
*/
private function getContent()
@@ -119,7 +116,7 @@ public function getLastParagraphStyle()
*
* @param mixed $value
*/
- public function setLastParagraphStyle($value = '')
+ public function setLastParagraphStyle($value = ''): void
{
$this->lastParagraphStyle = $value;
}
diff --git a/src/PhpWord/Writer/RTF/Element/AbstractElement.php b/src/PhpWord/Writer/RTF/Element/AbstractElement.php
index cf1aa391c5..e007e6aa26 100644
--- a/src/PhpWord/Writer/RTF/Element/AbstractElement.php
+++ b/src/PhpWord/Writer/RTF/Element/AbstractElement.php
@@ -1,4 +1,5 @@
parentWriter = $parentWriter;
+ $this->element = $element;
+ $this->withoutP = $withoutP;
$this->escaper = new Rtf();
}
/**
* Get font and paragraph styles.
*/
- protected function getStyles()
+ 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 */
@@ -98,7 +132,7 @@ protected function getStyles()
}
/**
- * Write opening
+ * Write opening.
*
* @return string
*/
@@ -115,9 +149,10 @@ protected function writeOpening()
}
/**
- * Write text
+ * Write text.
*
* @param string $text
+ *
* @return string
*/
protected function writeText($text)
@@ -126,11 +161,11 @@ 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.
}
/**
- * Write closing
+ * Write closing.
*
* @return string
*/
@@ -144,7 +179,7 @@ protected function writeClosing()
}
/**
- * Write font style
+ * Write font style.
*
* @return string
*/
@@ -154,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 58c19256dc..dcac8ec071 100644
--- a/src/PhpWord/Writer/RTF/Element/Container.php
+++ b/src/PhpWord/Writer/RTF/Element/Container.php
@@ -1,4 +1,5 @@
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/Field.php b/src/PhpWord/Writer/RTF/Element/Field.php
new file mode 100644
index 0000000000..c5e49c1d44
--- /dev/null
+++ b/src/PhpWord/Writer/RTF/Element/Field.php
@@ -0,0 +1,94 @@
+element;
+ if (!$element instanceof ElementField) {
+ 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 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';
+ $properties = $element->getProperties();
+ if (isset($properties['dateformat'])) {
+ $content .= ' \\\\@ "' . $properties['dateformat'] . '"';
+ }
+
+ return $content;
+ }
+}
diff --git a/src/PhpWord/Writer/RTF/Element/Image.php b/src/PhpWord/Writer/RTF/Element/Image.php
index f1e727007b..53052c85e7 100644
--- a/src/PhpWord/Writer/RTF/Element/Image.php
+++ b/src/PhpWord/Writer/RTF/Element/Image.php
@@ -1,4 +1,5 @@
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/Table.php b/src/PhpWord/Writer/RTF/Element/Table.php
index 8154aa7cf5..3b08a5db86 100644
--- a/src/PhpWord/Writer/RTF/Element/Table.php
+++ b/src/PhpWord/Writer/RTF/Element/Table.php
@@ -1,4 +1,5 @@
element->getStyle();
+ $bidiStyle = (is_object($style) && method_exists($style, 'isBidiVisual')) ? $style->isBidiVisual() : Settings::isDefaultRtl();
+ $bidi = $bidiStyle ? '\rtlrow' : '';
$rows = $element->getRows();
$rowCount = count($rows);
if ($rowCount > 0) {
$content .= '\pard' . PHP_EOL;
- for ($i = 0; $i < $rowCount; $i++) {
- $content .= '\trowd ';
+ for ($i = 0; $i < $rowCount; ++$i) {
+ $content .= "\\trowd$bidi ";
$content .= $this->writeRowDef($rows[$i]);
$content .= PHP_EOL;
$content .= $this->writeRow($rows[$i]);
$content .= '\row' . PHP_EOL;
}
+ $content .= '\pard' . PHP_EOL;
}
return $content;
}
/**
- * Write column
+ * Write column.
*
- * @param \PhpOffice\PhpWord\Element\Row $row
* @return string
*/
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) {
$width = 720; // Arbitrary default width
}
$rightMargin += $width;
- $content .= "{$vMerge}\cellx{$rightMargin} ";
+ $content .= "{$vMerge}\\cellx{$rightMargin} ";
}
return $content;
}
/**
- * Write row
+ * Write row.
*
- * @param \PhpOffice\PhpWord\Element\Row $row
* @return string
*/
private function writeRow(RowElement $row)
@@ -106,9 +128,8 @@ private function writeRow(RowElement $row)
}
/**
- * Write cell
+ * Write cell.
*
- * @param \PhpOffice\PhpWord\Element\Cell $cell
* @return string
*/
private function writeCell(CellElement $cell)
@@ -124,11 +145,110 @@ 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
+ * Get vertical merge style.
*
* @param string $value
+ *
* @return string
+ *
* @todo Move to style
*/
private function getVMerge($value)
diff --git a/src/PhpWord/Writer/RTF/Element/Text.php b/src/PhpWord/Writer/RTF/Element/Text.php
index b9e56e890b..71d3a27ce8 100644
--- a/src/PhpWord/Writer/RTF/Element/Text.php
+++ b/src/PhpWord/Writer/RTF/Element/Text.php
@@ -1,4 +1,5 @@
element;
- $elementClass = str_replace('\\Writer\\RTF', '', get_class($this));
+ $elementClass = str_replace('\\Writer\\RTF', '', static::class);
if (!$element instanceof $elementClass || !is_string($element->getText())) {
return '';
}
diff --git a/src/PhpWord/Writer/RTF/Element/TextBreak.php b/src/PhpWord/Writer/RTF/Element/TextBreak.php
index 4aab27677a..d74bf23dcb 100644
--- a/src/PhpWord/Writer/RTF/Element/TextBreak.php
+++ b/src/PhpWord/Writer/RTF/Element/TextBreak.php
@@ -1,4 +1,5 @@
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..06266897b3 100644
--- a/src/PhpWord/Writer/RTF/Element/Title.php
+++ b/src/PhpWord/Writer/RTF/Element/Title.php
@@ -1,4 +1,5 @@
element;
+ $style = $element->getStyle();
+ $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\Title $element Type hint */
+ $element = $this->element;
+ $elementClass = str_replace('\\Writer\\RTF', '', static::class);
+ 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 = '';
+
+ $content .= $this->writeOpening();
+ $endout = '';
+ $style = $element->getStyle();
+ if (is_string($style)) {
+ $style = str_replace('Heading', '', $style);
+ if ("$style" !== '') {
+ $style = (int) $style - 1;
+ if ($style >= 0 && $style <= 8) {
+ $content .= '{\\outlinelevel' . $style;
+ $endout = '}';
+ }
+ }
+ }
+
+ $content .= '{';
+ $content .= $this->writeFontStyle();
+ $content .= $this->writeText($textToWrite);
+ $content .= '}';
+ $content .= $this->writeClosing();
+ $content .= $endout;
+
+ return $content;
+ }
}
diff --git a/src/PhpWord/Writer/RTF/Part/AbstractPart.php b/src/PhpWord/Writer/RTF/Part/AbstractPart.php
index 8171b0d228..a07f70bbf7 100644
--- a/src/PhpWord/Writer/RTF/Part/AbstractPart.php
+++ b/src/PhpWord/Writer/RTF/Part/AbstractPart.php
@@ -1,4 +1,5 @@
parentWriter = $writer;
}
/**
- * @throws \PhpOffice\PhpWord\Exception\Exception
- * @return \PhpOffice\PhpWord\Writer\AbstractWriter
+ * @return \PhpOffice\PhpWord\Writer\RTF
*/
public function getParentWriter()
{
if ($this->parentWriter !== null) {
return $this->parentWriter;
}
+
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 d4bfadb4c5..484393477d 100644
--- a/src/PhpWord/Writer/RTF/Part/Document.php
+++ b/src/PhpWord/Writer/RTF/Part/Document.php
@@ -1,4 +1,5 @@
getParentWriter()->getPhpWord()->getDocInfo();
- $properties = array('title', 'subject', 'category', 'keywords', 'comment',
- 'author', 'operator', 'creatim', 'revtim', 'company', 'manager', );
- $mapping = array(
- 'comment' => 'description',
- 'author' => 'creator',
+ $properties = [
+ 'title' => 'title',
+ 'subject' => 'subject',
+ 'category' => 'category',
+ 'keywords' => 'keywords',
+ 'comment' => 'description',
+ 'author' => 'creator',
'operator' => 'lastModifiedBy',
- 'creatim' => 'created',
- 'revtim' => 'modified', );
- $dateFields = array('creatim', 'revtim');
+ 'creatim' => 'created',
+ 'revtim' => 'modified',
+ 'company' => 'company',
+ 'manager' => 'manager',
+ ];
+ $dateFields = ['creatim', 'revtim'];
$content = '';
$content .= '{';
$content .= '\info';
- foreach ($properties as $property) {
- $method = 'get' . (isset($mapping[$property]) ? $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}}";
}
@@ -84,7 +92,7 @@ private function writeInfo()
}
/**
- * Write document formatting properties
+ * Write document formatting properties.
*
* @return string
*/
@@ -105,13 +113,39 @@ 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 sections
+ * Write titlepg directive if any "f" headers or footers.
+ *
+ * @param \PhpOffice\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.
*
* @return string
*/
@@ -120,38 +154,86 @@ private function writeSections()
$content = '';
$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();
+ $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();
-
- $content .= '\sect' . PHP_EOL;
}
return $content;
}
/**
- * Get date value
+ * Get date value.
*
* The format of date value is `\yr?\mo?\dy?\hr?\min?\sec?`
*
* @param int $value
+ *
* @return string
*/
private function getDateValue($value)
{
- $dateParts = array(
+ $dateParts = [
'Y' => 'yr',
'm' => 'mo',
'd' => 'dy',
'H' => 'hr',
'i' => 'min',
's' => 'sec',
- );
+ ];
$result = '';
foreach ($dateParts as $dateFormat => $controlWord) {
$result .= '\\' . $controlWord . date($dateFormat, $value);
diff --git a/src/PhpWord/Writer/RTF/Part/Header.php b/src/PhpWord/Writer/RTF/Part/Header.php
index 01439bc6ad..97644fe4ac 100644
--- a/src/PhpWord/Writer/RTF/Part/Header.php
+++ b/src/PhpWord/Writer/RTF/Part/Header.php
@@ -1,4 +1,5 @@
colorTable as $color) {
- list($red, $green, $blue) = Converter::htmlToRgb($color);
+ [$red, $green, $blue] = Converter::htmlToRgb($color);
$content .= "\\red{$red}\\green{$green}\\blue{$blue};";
}
$content .= '}';
@@ -165,7 +167,7 @@ private function writeColorTable()
}
/**
- * Write
+ * Write.
*
* @return string
*/
@@ -182,7 +184,7 @@ private function writeGenerator()
/**
* Register all fonts and colors in both named and inline styles to appropriate header table.
*/
- private function registerFont()
+ private function registerFont(): void
{
$phpWord = $this->getParentWriter()->getPhpWord();
$this->fontTable[] = Settings::getDefaultFontName();
@@ -210,9 +212,9 @@ private function registerFont()
/**
* Register border colors.
*
- * @param \PhpOffice\PhpWord\Style\Border $style
+ * @param Style\Border $style
*/
- private function registerBorderColor($style)
+ private function registerBorderColor($style): void
{
$colors = $style->getBorderColor();
foreach ($colors as $color) {
@@ -225,9 +227,9 @@ private function registerBorderColor($style)
/**
* Register fonts and colors.
*
- * @param \PhpOffice\PhpWord\Style\AbstractStyle $style
+ * @param Style\AbstractStyle $style
*/
- private function registerFontItems($style)
+ private function registerFontItems($style): void
{
$defaultFont = Settings::getDefaultFontName();
$defaultColor = Settings::DEFAULT_FONT_COLOR;
@@ -236,6 +238,14 @@ private function registerFontItems($style)
$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);
}
}
@@ -246,7 +256,7 @@ private function registerFontItems($style)
* @param string $value
* @param string $default
*/
- private function registerTableItem(&$table, $value, $default = null)
+ private function registerTableItem(&$table, $value, $default = null): void
{
if (in_array($value, $table) === false && $value !== null && $value != $default) {
$table[] = $value;
diff --git a/src/PhpWord/Writer/RTF/Style/AbstractStyle.php b/src/PhpWord/Writer/RTF/Style/AbstractStyle.php
index 57aa6bb9f7..00e148dfe9 100644
--- a/src/PhpWord/Writer/RTF/Style/AbstractStyle.php
+++ b/src/PhpWord/Writer/RTF/Style/AbstractStyle.php
@@ -1,4 +1,5 @@
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/Border.php b/src/PhpWord/Writer/RTF/Style/Border.php
index db97c28d00..c8dc943579 100644
--- a/src/PhpWord/Writer/RTF/Style/Border.php
+++ b/src/PhpWord/Writer/RTF/Style/Border.php
@@ -1,4 +1,5 @@
sizes);
// Page border measure
// 8 = from text, infront off; 32 = from edge, infront on; 40 = from edge, infront off
$content .= '\pgbrdropt32';
- for ($i = 0; $i < $sizeCount; $i++) {
+ for ($i = 0; $i < $sizeCount; ++$i) {
if ($this->sizes[$i] !== null) {
$color = null;
if (isset($this->colors[$i])) {
@@ -68,11 +69,12 @@ public function write()
}
/**
- * Write side
+ * Write side.
*
* @param string $side
* @param int $width
* @param string $color
+ *
* @return string
*/
private function writeSide($side, $width, $color = '')
@@ -83,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;
}
}
@@ -105,7 +107,7 @@ private function writeSide($side, $width, $color = '')
*
* @param int[] $value
*/
- public function setSizes($value)
+ public function setSizes($value): void
{
$this->sizes = $value;
}
@@ -115,7 +117,7 @@ public function setSizes($value)
*
* @param string[] $value
*/
- public function setColors($value)
+ public function setColors($value): void
{
$this->colors = $value;
}
diff --git a/src/PhpWord/Writer/RTF/Style/Font.php b/src/PhpWord/Writer/RTF/Style/Font.php
index b9001ea0ea..f343c0502f 100644
--- a/src/PhpWord/Writer/RTF/Style/Font.php
+++ b/src/PhpWord/Writer/RTF/Style/Font.php
@@ -1,4 +1,5 @@
getValueIf($style->isRTL(), '\rtlch');
$content .= '\cf' . $this->colorIndex;
$content .= '\f' . $this->nameIndex;
@@ -68,10 +70,9 @@ public function write()
/**
* Set font name index.
*
- *
* @param int $value
*/
- public function setNameIndex($value = 0)
+ public function setNameIndex($value = 0): void
{
$this->nameIndex = $value;
}
@@ -81,7 +82,7 @@ public function setNameIndex($value = 0)
*
* @param int $value
*/
- public function setColorIndex($value = 0)
+ public function setColorIndex($value = 0): void
{
$this->colorIndex = $value;
}
diff --git a/src/PhpWord/Writer/RTF/Style/Indentation.php b/src/PhpWord/Writer/RTF/Style/Indentation.php
index 50e8ad9940..589125a26a 100644
--- a/src/PhpWord/Writer/RTF/Style/Indentation.php
+++ b/src/PhpWord/Writer/RTF/Style/Indentation.php
@@ -1,4 +1,5 @@
'\ql',
- Jc::END => '\qr',
+ $alignments = [
+ Jc::START => '\ql',
+ Jc::END => '\qr',
Jc::CENTER => '\qc',
- Jc::BOTH => '\qj',
- );
+ 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();
$spaceBefore = $style->getSpaceBefore();
@@ -61,12 +78,25 @@ 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));
- $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);
+ $content .= "\\sl$lineHeightAdjusted\\slmult1";
+ }
+ if ($style->hasPageBreakBefore()) {
+ $content .= '\\page';
+ }
$styles = $style->getStyleValues();
$content .= $this->writeTabs($styles['tabs']);
@@ -75,9 +105,10 @@ public function write()
}
/**
- * Writes an \PhpOffice\PhpWord\Style\Indentation
+ * Writes an \PhpOffice\PhpWord\Style\Indentation.
*
* @param null|\PhpOffice\PhpWord\Style\Indentation $indent
+ *
* @return string
*/
private function writeIndentation($indent = null)
@@ -92,9 +123,10 @@ private function writeIndentation($indent = null)
}
/**
- * Writes tabs
+ * Writes tabs.
*
* @param \PhpOffice\PhpWord\Style\Tab[] $tabs
+ *
* @return string
*/
private function writeTabs($tabs = null)
@@ -115,7 +147,7 @@ private function writeTabs($tabs = null)
*
* @param int $value
*/
- public function setNestedLevel($value)
+ public function setNestedLevel($value): void
{
$this->nestedLevel = $value;
}
diff --git a/src/PhpWord/Writer/RTF/Style/Section.php b/src/PhpWord/Writer/RTF/Style/Section.php
index 190bb67036..598015ed4d 100644
--- a/src/PhpWord/Writer/RTF/Style/Section.php
+++ b/src/PhpWord/Writer/RTF/Style/Section.php
@@ -1,4 +1,5 @@
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/src/PhpWord/Writer/RTF/Style/Tab.php b/src/PhpWord/Writer/RTF/Style/Tab.php
index a21b13d39d..95e1f10a5c 100644
--- a/src/PhpWord/Writer/RTF/Style/Tab.php
+++ b/src/PhpWord/Writer/RTF/Style/Tab.php
@@ -1,4 +1,5 @@
'\tqr',
- \PhpOffice\PhpWord\Style\Tab::TAB_STOP_CENTER => '\tqc',
+ $tabs = [
+ \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()];
diff --git a/src/PhpWord/Writer/Word2007.php b/src/PhpWord/Writer/Word2007.php
index eee215bef0..9702c210bd 100644
--- a/src/PhpWord/Writer/Word2007.php
+++ b/src/PhpWord/Writer/Word2007.php
@@ -1,4 +1,5 @@
array(), 'override' => array());
+ private $contentTypes = ['default' => [], 'override' => []];
/**
- * Document relationship
+ * Document relationship.
*
* @var array
*/
- private $relationships = array();
+ private $relationships = [];
/**
- * Create new Word2007 writer
- *
- * @param \PhpOffice\PhpWord\PhpWord
+ * Create new Word2007 writer.
*/
- public function __construct(PhpWord $phpWord = null)
+ public function __construct(?PhpWord $phpWord = null)
{
// Assign PhpWord
$this->setPhpWord($phpWord);
// Create parts
- $this->parts = array(
- 'ContentTypes' => '[Content_Types].xml',
- 'Rels' => '_rels/.rels',
- 'DocPropsApp' => 'docProps/app.xml',
- 'DocPropsCore' => 'docProps/core.xml',
+ // 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',
- 'Settings' => 'word/settings.xml',
- 'WebSettings' => 'word/webSettings.xml',
- 'FontTable' => 'word/fontTable.xml',
- 'Theme' => 'word/theme/theme1.xml',
- 'RelsPart' => '',
- 'Header' => '',
- 'Footer' => '',
- 'Footnotes' => '',
- 'Endnotes' => '',
- 'Chart' => '',
- );
+ 'Comments' => 'word/comments.xml',
+ 'Styles' => 'word/styles.xml',
+ 'Numbering' => 'word/numbering.xml',
+ 'Settings' => 'word/settings.xml',
+ 'WebSettings' => 'word/webSettings.xml',
+ 'FontTable' => 'word/fontTable.xml',
+ 'Theme' => 'word/theme/theme1.xml',
+ 'RelsPart' => '',
+ 'Header' => '',
+ 'Footer' => '',
+ 'Footnotes' => '',
+ 'Endnotes' => '',
+ 'Chart' => '',
+ ];
foreach (array_keys($this->parts) as $partName) {
- $partClass = get_class($this) . '\\Part\\' . $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;
@@ -85,25 +85,23 @@ public function __construct(PhpWord $phpWord = null)
}
// Set package paths
- $this->mediaPaths = array('image' => 'word/media/', 'object' => 'word/embeddings/');
+ $this->mediaPaths = ['image' => 'word/media/', 'object' => 'word/embeddings/'];
}
/**
* Save document by name.
- *
- * @param string $filename
*/
- public function save($filename = null)
+ public function save(string $filename): void
{
$filename = $this->getTempFile($filename);
$zip = $this->getZipArchive($filename);
$phpWord = $this->getPhpWord();
// Content types
- $this->contentTypes['default'] = array(
+ $this->contentTypes['default'] = [
'rels' => 'application/vnd.openxmlformats-package.relationships+xml',
- 'xml' => 'application/xml',
- );
+ 'xml' => 'application/xml',
+ ];
// Add section media files
$sectionMedia = Media::getElements('section');
@@ -120,7 +118,7 @@ public function save($filename = null)
$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);
@@ -145,7 +143,7 @@ public function save($filename = null)
}
/**
- * Get content types
+ * Get content types.
*
* @return array
*/
@@ -155,7 +153,7 @@ public function getContentTypes()
}
/**
- * Get content types
+ * Get content types.
*
* @return array
*/
@@ -167,10 +165,9 @@ public function getRelationships()
/**
* Add header/footer media files, e.g. footer1.xml.rels.
*
- * @param \PhpOffice\PhpWord\Shared\ZipArchive $zip
* @param string $docPart
*/
- private function addHeaderFooterMedia(ZipArchive $zip, $docPart)
+ private function addHeaderFooterMedia(ZipArchive $zip, $docPart): void
{
$elements = Media::getElements($docPart);
if (!empty($elements)) {
@@ -181,7 +178,7 @@ private function addHeaderFooterMedia(ZipArchive $zip, $docPart)
$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());
}
@@ -192,57 +189,53 @@ private function addHeaderFooterMedia(ZipArchive $zip, $docPart)
/**
* Add header/footer content.
*
- * @param \PhpOffice\PhpWord\Element\Section &$section
- * @param \PhpOffice\PhpWord\Shared\ZipArchive $zip
* @param string $elmType header|footer
* @param int &$rId
*/
- private function addHeaderFooterContent(Section &$section, ZipArchive $zip, $elmType, &$rId)
+ private function addHeaderFooterContent(Section &$section, ZipArchive $zip, $elmType, &$rId): void
{
$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) {
- $elmCount++;
+ ++$elmCount;
$element->setRelationId(++$rId);
$elmFile = "{$elmType}{$elmCount}.xml"; // e.g. footer1.xml
$this->contentTypes['override']["/word/$elmFile"] = $elmType;
- $this->relationships[] = array('target' => $elmFile, 'type' => $elmType, 'rID' => $rId);
+ $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());
}
}
/**
- * Add footnotes/endnotes
+ * Add footnotes/endnotes.
*
- * @param \PhpOffice\PhpWord\Shared\ZipArchive $zip
* @param int &$rId
* @param string $noteType
*/
- private function addNotes(ZipArchive $zip, &$rId, $noteType = 'footnote')
+ 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
- /** @var \PhpOffice\PhpWord\Collection\AbstractCollection $collection Type hint */
if ($collection->countItems() > 0) {
$media = Media::getElements($noteType);
$this->addFilesToPackage($zip, $media);
$this->registerContentTypes($media);
$this->contentTypes['override']["/word/{$partName}.xml"] = $partName;
- $this->relationships[] = array('target' => "{$partName}.xml", 'type' => $partName, 'rID' => ++$rId);
+ $this->relationships[] = ['target' => "{$partName}.xml", 'type' => $partName, 'rID' => ++$rId];
// 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());
}
@@ -254,21 +247,19 @@ private function addNotes(ZipArchive $zip, &$rId, $noteType = 'footnote')
}
/**
- * Add comments
+ * Add comments.
*
- * @param \PhpOffice\PhpWord\Shared\ZipArchive $zip
* @param int &$rId
*/
- private function addComments(ZipArchive $zip, &$rId)
+ private function addComments(ZipArchive $zip, &$rId): void
{
$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);
+ $this->relationships[] = ['target' => "{$partName}.xml", 'type' => $partName, 'rID' => ++$rId];
// Write content file, e.g. word/comments.xml
$writerPart = $this->getWriterPart($partName)->setElements($collection->getItems());
@@ -279,10 +270,9 @@ private function addComments(ZipArchive $zip, &$rId)
/**
* Add chart.
*
- * @param \PhpOffice\PhpWord\Shared\ZipArchive $zip
* @param int &$rId
*/
- private function addChart(ZipArchive $zip, &$rId)
+ private function addChart(ZipArchive $zip, &$rId): void
{
$phpWord = $this->getPhpWord();
@@ -291,15 +281,15 @@ private function addChart(ZipArchive $zip, &$rId)
if ($collection->countItems() > 0) {
/** @var \PhpOffice\PhpWord\Element\Chart $chart */
foreach ($collection->getItems() as $chart) {
- $index++;
- $rId++;
+ ++$index;
+ ++$rId;
$filename = "charts/chart{$index}.xml";
// ContentTypes.xml
$this->contentTypes['override']["/word/{$filename}"] = 'chart';
// word/_rels/document.xml.rel
- $this->relationships[] = array('target' => $filename, 'type' => 'chart', 'rID' => $rId);
+ $this->relationships[] = ['target' => $filename, 'type' => 'chart', 'rID' => $rId];
// word/charts/chartN.xml
$chart->setRelationId($rId);
@@ -315,7 +305,7 @@ private function addChart(ZipArchive $zip, &$rId)
*
* @param array $media
*/
- private function registerContentTypes($media)
+ private function registerContentTypes($media): void
{
foreach ($media as $medium) {
$mediumType = $medium['type'];
diff --git a/src/PhpWord/Writer/Word2007/Element/AbstractElement.php b/src/PhpWord/Writer/Word2007/Element/AbstractElement.php
index 63f45a761f..5743c8c7c7 100644
--- a/src/PhpWord/Writer/Word2007/Element/AbstractElement.php
+++ b/src/PhpWord/Writer/Word2007/Element/AbstractElement.php
@@ -1,4 +1,5 @@
xmlWriter = $xmlWriter;
$this->element = $element;
@@ -70,9 +73,9 @@ public function __construct(XMLWriter $xmlWriter, Element $element, $withoutP =
}
/**
- * Get XML Writer
+ * Get XML Writer.
*
- * @return \PhpOffice\Common\XMLWriter
+ * @return XMLWriter
*/
protected function getXmlWriter()
{
@@ -80,9 +83,9 @@ protected function getXmlWriter()
}
/**
- * Get element
+ * Get element.
*
- * @return \PhpOffice\PhpWord\Element\AbstractElement
+ * @return Element
*/
protected function getElement()
{
@@ -94,7 +97,7 @@ protected function getElement()
*
* @uses \PhpOffice\PhpWord\Writer\Word2007\Element\PageBreak::write()
*/
- protected function startElementP()
+ protected function startElementP(): void
{
if (!$this->withoutP) {
$this->xmlWriter->startElement('w:p');
@@ -109,7 +112,7 @@ protected function startElementP()
/**
* End w:p DOM element.
*/
- protected function endElementP()
+ protected function endElementP(): void
{
$this->writeCommentRangeEnd();
if (!$this->withoutP) {
@@ -118,55 +121,46 @@ protected function endElementP()
}
/**
- * Writes the w:commentRangeStart DOM element
+ * Writes the w:commentRangeStart DOM element.
*/
- protected function writeCommentRangeStart()
+ 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', array('w:id' => $comment->getElementId()));
}
}
/**
- * Writes the w:commentRangeEnd DOM element
+ * Writes the w:commentRangeEnd DOM element.
*/
- protected function writeCommentRangeEnd()
+ 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', 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, this should normally not happen
- if ($comment->getElementId() == null) {
- $comment->setElementId(); // @codeCoverageIgnore
- } // @codeCoverageIgnore
-
- $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();
+ 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();
+ }
+ }
}
}
/**
* Write ending.
*/
- protected function writeParagraphStyle()
+ protected function writeParagraphStyle(): void
{
$this->writeTextStyle('Paragraph');
}
@@ -174,7 +168,7 @@ protected function writeParagraphStyle()
/**
* Write ending.
*/
- protected function writeFontStyle()
+ protected function writeFontStyle(): void
{
$this->writeTextStyle('Font');
}
@@ -184,7 +178,7 @@ protected function writeFontStyle()
*
* @param string $styleType Font|Paragraph
*/
- private function writeTextStyle($styleType)
+ private function writeTextStyle($styleType): void
{
$method = "get{$styleType}Style";
$class = "PhpOffice\\PhpWord\\Writer\\Word2007\\Style\\{$styleType}";
@@ -200,20 +194,22 @@ private function writeTextStyle($styleType)
}
/**
- * Convert text to valid format
+ * Convert text to valid format.
*
* @param string $text
+ *
* @return string
*/
protected function getText($text)
{
- return CommonText::controlCharacterPHP2OOXML($text);
+ return SharedText::controlCharacterPHP2OOXML($text);
}
/**
- * Write an XML text, this will call text() or writeRaw() depending on the value of Settings::isOutputEscapingEnabled()
+ * 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)
@@ -224,4 +220,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/Bookmark.php b/src/PhpWord/Writer/Word2007/Element/Bookmark.php
index 04eaacf37c..ba61ad69fd 100644
--- a/src/PhpWord/Writer/Word2007/Element/Bookmark.php
+++ b/src/PhpWord/Writer/Word2007/Element/Bookmark.php
@@ -1,4 +1,5 @@
getXmlWriter();
$element = $this->getElement();
diff --git a/src/PhpWord/Writer/Word2007/Element/Chart.php b/src/PhpWord/Writer/Word2007/Element/Chart.php
index f88ca2d252..6d4e18a9e4 100644
--- a/src/PhpWord/Writer/Word2007/Element/Chart.php
+++ b/src/PhpWord/Writer/Word2007/Element/Chart.php
@@ -1,4 +1,5 @@
getXmlWriter();
$element = $this->getElement();
@@ -50,8 +51,8 @@ public function write()
$xmlWriter->startElement('wp:inline');
// EMU
- $xmlWriter->writeElementBlock('wp:extent', array('cx' => $style->getWidth(), 'cy' => $style->getHeight()));
- $xmlWriter->writeElementBlock('wp:docPr', array('id' => $rId, 'name' => "Chart{$rId}"));
+ $xmlWriter->writeElementBlock('wp:extent', ['cx' => $style->getWidth(), 'cy' => $style->getHeight()]);
+ $xmlWriter->writeElementBlock('wp:docPr', ['id' => $rId, 'name' => "Chart{$rId}"]);
$xmlWriter->startElement('a:graphic');
$xmlWriter->writeAttribute('xmlns:a', 'http://schemas.openxmlformats.org/drawingml/2006/main');
diff --git a/src/PhpWord/Writer/Word2007/Element/CheckBox.php b/src/PhpWord/Writer/Word2007/Element/CheckBox.php
index 05692a074d..1adf7d6eb1 100644
--- a/src/PhpWord/Writer/Word2007/Element/CheckBox.php
+++ b/src/PhpWord/Writer/Word2007/Element/CheckBox.php
@@ -1,4 +1,5 @@
getXmlWriter();
$element = $this->getElement();
diff --git a/src/PhpWord/Writer/Word2007/Element/Container.php b/src/PhpWord/Writer/Word2007/Element/Container.php
index 892da051ad..85386f0b18 100644
--- a/src/PhpWord/Writer/Word2007/Element/Container.php
+++ b/src/PhpWord/Writer/Word2007/Element/Container.php
@@ -1,4 +1,5 @@
+ */
+ protected $containerWithoutP = ['TextRun', 'Footnote', 'Endnote', 'ListItemRun'];
+
/**
* Write element.
*/
- public function write()
+ public function write(): void
{
$container = $this->getElement();
if (!$container instanceof ContainerElement) {
return;
}
$containerClass = substr(get_class($container), strrpos(get_class($container), '\\') + 1);
- $withoutP = in_array($containerClass, array('TextRun', 'Footnote', 'Endnote', 'ListItemRun'));
+ $withoutP = in_array($containerClass, $this->containerWithoutP);
$xmlWriter = $this->getXmlWriter();
// Loop through elements
@@ -62,28 +68,24 @@ public function write()
$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();
}
}
/**
- * Write individual element
- *
- * @param \PhpOffice\Common\XMLWriter $xmlWriter
- * @param \PhpOffice\PhpWord\Element\AbstractElement $element
- * @param bool $withoutP
- * @return string
+ * Write individual element.
*/
- 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;
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 9a2eb3ffab..6a00ed5b3b 100644
--- a/src/PhpWord/Writer/Word2007/Element/Endnote.php
+++ b/src/PhpWord/Writer/Word2007/Element/Endnote.php
@@ -1,4 +1,5 @@
getElement();
- if (!$element instanceof \PhpOffice\PhpWord\Element\Field) {
+ if (!$element instanceof ElementField) {
return;
}
@@ -42,7 +46,7 @@ public function write()
}
}
- private function writeDefault(\PhpOffice\PhpWord\Element\Field $element)
+ private function writeDefault(ElementField $element): void
{
$xmlWriter = $this->getXmlWriter();
$this->startElementP();
@@ -65,6 +69,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);
@@ -72,7 +77,7 @@ private function writeDefault(\PhpOffice\PhpWord\Element\Field $element)
$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();
@@ -115,12 +120,11 @@ private function writeDefault(\PhpOffice\PhpWord\Element\Field $element)
}
/**
- * Writes a macrobutton field
+ * 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)
+ protected function writeMacrobutton(ElementField $element): void
{
$xmlWriter = $this->getXmlWriter();
$this->startElementP();
@@ -144,7 +148,7 @@ protected function writeMacrobutton(\PhpOffice\PhpWord\Element\Field $element)
$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();
}
@@ -159,26 +163,31 @@ 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();
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':
$propertiesAndOptions .= $propval . ' ';
+
break;
default:
$propertiesAndOptions .= '"' . $propval . '" ';
+
break;
}
}
@@ -187,22 +196,32 @@ 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:
$propertiesAndOptions .= $option . ' ';
@@ -211,4 +230,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 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/src/PhpWord/Writer/Word2007/Element/Footnote.php b/src/PhpWord/Writer/Word2007/Element/Footnote.php
index 56a5332f07..68f998e390 100644
--- a/src/PhpWord/Writer/Word2007/Element/Footnote.php
+++ b/src/PhpWord/Writer/Word2007/Element/Footnote.php
@@ -1,4 +1,5 @@
getXmlWriter();
$element = $this->getElement();
@@ -51,7 +52,7 @@ public function write()
$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/Element/FormField.php b/src/PhpWord/Writer/Word2007/Element/FormField.php
index b59cf58f89..1e58f58e55 100644
--- a/src/PhpWord/Writer/Word2007/Element/FormField.php
+++ b/src/PhpWord/Writer/Word2007/Element/FormField.php
@@ -1,4 +1,5 @@
getXmlWriter();
$element = $this->getElement();
@@ -46,7 +48,7 @@ public function write()
}
$type = $element->getType();
- $instructions = array('textinput' => 'FORMTEXT', 'checkbox' => 'FORMCHECKBOX', 'dropdown' => 'FORMDROPDOWN');
+ $instructions = ['textinput' => 'FORMTEXT', 'checkbox' => 'FORMCHECKBOX', 'dropdown' => 'FORMDROPDOWN'];
$instruction = $instructions[$type];
$writeFormField = "write{$type}";
$name = $element->getName();
@@ -105,10 +107,8 @@ 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\Element\FormField $element
*/
- private function writeTextInput(XMLWriter $xmlWriter, FormFieldElement $element)
+ private function writeTextInput(XMLWriter $xmlWriter, FormFieldElement $element): void
{
$default = $element->getDefault();
@@ -121,10 +121,8 @@ 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\Element\FormField $element
*/
- private function writeCheckBox(XMLWriter $xmlWriter, FormFieldElement $element)
+ private function writeCheckBox(XMLWriter $xmlWriter, FormFieldElement $element): void
{
$default = $element->getDefault() ? 1 : 0;
$value = $element->getValue();
@@ -144,10 +142,8 @@ 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\Element\FormField $element
*/
- private function writeDropDown(XMLWriter $xmlWriter, FormFieldElement $element)
+ private function writeDropDown(XMLWriter $xmlWriter, FormFieldElement $element): void
{
$default = $element->getDefault();
$value = $element->getValue();
diff --git a/src/PhpWord/Writer/Word2007/Element/Formula.php b/src/PhpWord/Writer/Word2007/Element/Formula.php
new file mode 100644
index 0000000000..9556706221
--- /dev/null
+++ b/src/PhpWord/Writer/Word2007/Element/Formula.php
@@ -0,0 +1,51 @@
+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/src/PhpWord/Writer/Word2007/Element/Image.php b/src/PhpWord/Writer/Word2007/Element/Image.php
index 5bebb89c05..7835f32ad5 100644
--- a/src/PhpWord/Writer/Word2007/Element/Image.php
+++ b/src/PhpWord/Writer/Word2007/Element/Image.php
@@ -1,4 +1,5 @@
getXmlWriter();
$element = $this->getElement();
@@ -52,7 +53,7 @@ public function write()
/**
* Write image element.
*/
- private function writeImage(XMLWriter $xmlWriter, ImageElement $element)
+ private function writeImage(XMLWriter $xmlWriter, ImageElement $element): void
{
$rId = $element->getRelationId() + ($element->isInSection() ? 6 : 0);
$style = $element->getStyle();
@@ -78,6 +79,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();
@@ -96,7 +98,7 @@ private function writeImage(XMLWriter $xmlWriter, ImageElement $element)
/**
* Write watermark element.
*/
- private function writeWatermark(XMLWriter $xmlWriter, ImageElement $element)
+ private function writeWatermark(XMLWriter $xmlWriter, ImageElement $element): void
{
$rId = $element->getRelationId();
$style = $element->getStyle();
@@ -110,6 +112,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();
diff --git a/src/PhpWord/Writer/Word2007/Element/Line.php b/src/PhpWord/Writer/Word2007/Element/Line.php
index a114be6006..fe8370653a 100644
--- a/src/PhpWord/Writer/Word2007/Element/Line.php
+++ b/src/PhpWord/Writer/Word2007/Element/Line.php
@@ -1,4 +1,5 @@
getXmlWriter();
$element = $this->getElement();
diff --git a/src/PhpWord/Writer/Word2007/Element/Link.php b/src/PhpWord/Writer/Word2007/Element/Link.php
index f0adf851e3..563343899d 100644
--- a/src/PhpWord/Writer/Word2007/Element/Link.php
+++ b/src/PhpWord/Writer/Word2007/Element/Link.php
@@ -1,4 +1,5 @@
getXmlWriter();
$element = $this->getElement();
diff --git a/src/PhpWord/Writer/Word2007/Element/ListItem.php b/src/PhpWord/Writer/Word2007/Element/ListItem.php
index ef738e10d7..a91301cdc0 100644
--- a/src/PhpWord/Writer/Word2007/Element/ListItem.php
+++ b/src/PhpWord/Writer/Word2007/Element/ListItem.php
@@ -1,4 +1,5 @@
getXmlWriter();
$element = $this->getElement();
diff --git a/src/PhpWord/Writer/Word2007/Element/ListItemRun.php b/src/PhpWord/Writer/Word2007/Element/ListItemRun.php
index 765d2ee0f9..a20912a0a8 100644
--- a/src/PhpWord/Writer/Word2007/Element/ListItemRun.php
+++ b/src/PhpWord/Writer/Word2007/Element/ListItemRun.php
@@ -1,4 +1,5 @@
getXmlWriter();
$element = $this->getElement();
- if (!$element instanceof \PhpOffice\PhpWord\Element\ListItemRun) {
+
+ if (!$element instanceof ListItemRunElement) {
return;
}
+ $this->writeParagraph($element);
+ }
+
+ private function writeParagraph(ListItemRunElement $element): void
+ {
+ $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): void
+ {
+ $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): void
+ {
+ $xmlWriter = $this->getXmlWriter();
+ $xmlWriter->startElement('w:numPr');
- $xmlWriter->endElement(); // w:p
+ $xmlWriter->writeElementBlock('w:ilvl', [
+ 'w:val' => $element->getDepth(),
+ ]);
+
+ $xmlWriter->writeElementBlock('w:numId', [
+ 'w:val' => $element->getStyle()->getNumId(),
+ ]);
+
+ $xmlWriter->endElement(); // w:numPr
}
}
diff --git a/src/PhpWord/Writer/Word2007/Element/OLEObject.php b/src/PhpWord/Writer/Word2007/Element/OLEObject.php
index c55ff6cd8c..f7db89defe 100644
--- a/src/PhpWord/Writer/Word2007/Element/OLEObject.php
+++ b/src/PhpWord/Writer/Word2007/Element/OLEObject.php
@@ -1,4 +1,5 @@
getXmlWriter();
$element = $this->getElement();
diff --git a/src/PhpWord/Writer/Word2007/Element/PageBreak.php b/src/PhpWord/Writer/Word2007/Element/PageBreak.php
index 0801e4d3c4..2e9ba4f202 100644
--- a/src/PhpWord/Writer/Word2007/Element/PageBreak.php
+++ b/src/PhpWord/Writer/Word2007/Element/PageBreak.php
@@ -1,4 +1,5 @@
getXmlWriter();
diff --git a/src/PhpWord/Writer/Word2007/Element/ParagraphAlignment.php b/src/PhpWord/Writer/Word2007/Element/ParagraphAlignment.php
index 5563f6075d..2dbf229d63 100644
--- a/src/PhpWord/Writer/Word2007/Element/ParagraphAlignment.php
+++ b/src/PhpWord/Writer/Word2007/Element/ParagraphAlignment.php
@@ -1,4 +1,5 @@
getXmlWriter();
$element = $this->getElement();
@@ -37,7 +38,7 @@ public function write()
$texts = $element->getText();
if (!is_array($texts)) {
- $texts = array($texts);
+ $texts = [$texts];
}
$this->startElementP();
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 @@
+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/src/PhpWord/Writer/Word2007/Element/SDT.php b/src/PhpWord/Writer/Word2007/Element/SDT.php
index edf89b5387..dfe5ca9bca 100644
--- a/src/PhpWord/Writer/Word2007/Element/SDT.php
+++ b/src/PhpWord/Writer/Word2007/Element/SDT.php
@@ -1,4 +1,5 @@
getXmlWriter();
$element = $this->getElement();
@@ -56,7 +58,7 @@ public function write()
$xmlWriter->startElement('w:sdtPr');
$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->writeElementBlock('w:id', 'w:val', mt_rand(100000000, 999999999));
$xmlWriter->writeElementIf($tag != null, 'w:tag', 'w:val', $tag);
$this->$writeFormField($xmlWriter, $element);
$xmlWriter->endElement(); // w:sdtPr
@@ -77,9 +79,8 @@ public function write()
* Write text.
*
* @see http://www.datypic.com/sc/ooxml/t-w_CT_SdtText.html
- * @param \PhpOffice\Common\XMLWriter $xmlWriter
*/
- private function writePlainText(XMLWriter $xmlWriter)
+ private function writePlainText(XMLWriter $xmlWriter): void
{
$xmlWriter->startElement('w:text');
$xmlWriter->endElement(); // w:text
@@ -89,17 +90,15 @@ 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\Element\SDT $element
*/
- private function writeComboBox(XMLWriter $xmlWriter, SDTElement $element)
+ private function writeComboBox(XMLWriter $xmlWriter, SDTElement $element): void
{
$type = $element->getType();
$listItems = $element->getListItems();
$xmlWriter->startElement("w:{$type}");
foreach ($listItems as $key => $val) {
- $xmlWriter->writeElementBlock('w:listItem', array('w:value' => $key, 'w:displayText' => $val));
+ $xmlWriter->writeElementBlock('w:listItem', ['w:value' => $key, 'w:displayText' => $val]);
}
$xmlWriter->endElement(); // w:{$type}
}
@@ -108,10 +107,8 @@ 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\Element\SDT $element
*/
- private function writeDropDownList(XMLWriter $xmlWriter, SDTElement $element)
+ private function writeDropDownList(XMLWriter $xmlWriter, SDTElement $element): void
{
$this->writeComboBox($xmlWriter, $element);
}
@@ -120,10 +117,8 @@ 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\Element\SDT $element
*/
- private function writeDate(XMLWriter $xmlWriter, SDTElement $element)
+ private function writeDate(XMLWriter $xmlWriter, SDTElement $element): void
{
$type = $element->getType();
diff --git a/src/PhpWord/Writer/Word2007/Element/Shape.php b/src/PhpWord/Writer/Word2007/Element/Shape.php
index 250d5c1d0d..0af2831ba6 100644
--- a/src/PhpWord/Writer/Word2007/Element/Shape.php
+++ b/src/PhpWord/Writer/Word2007/Element/Shape.php
@@ -1,4 +1,5 @@
getXmlWriter();
$element = $this->getElement();
@@ -76,11 +78,8 @@ public function write()
/**
* Write arc.
- *
- * @param \PhpOffice\Common\XMLWriter $xmlWriter
- * @param \PhpOffice\PhpWord\Style\Shape $style
*/
- private function writeArc(XMLWriter $xmlWriter, ShapeStyle $style)
+ private function writeArc(XMLWriter $xmlWriter, ShapeStyle $style): void
{
$points = $this->getPoints('arc', $style->getPoints());
@@ -90,11 +89,8 @@ private function writeArc(XMLWriter $xmlWriter, ShapeStyle $style)
/**
* Write curve.
- *
- * @param \PhpOffice\Common\XMLWriter $xmlWriter
- * @param \PhpOffice\PhpWord\Style\Shape $style
*/
- private function writeCurve(XMLWriter $xmlWriter, ShapeStyle $style)
+ private function writeCurve(XMLWriter $xmlWriter, ShapeStyle $style): void
{
$points = $this->getPoints('curve', $style->getPoints());
@@ -105,11 +101,8 @@ private function writeCurve(XMLWriter $xmlWriter, ShapeStyle $style)
/**
* Write line.
- *
- * @param \PhpOffice\Common\XMLWriter $xmlWriter
- * @param \PhpOffice\PhpWord\Style\Shape $style
*/
- private function writeLine(XMLWriter $xmlWriter, ShapeStyle $style)
+ private function writeLine(XMLWriter $xmlWriter, ShapeStyle $style): void
{
$points = $this->getPoints('line', $style->getPoints());
@@ -119,48 +112,45 @@ private function writeLine(XMLWriter $xmlWriter, ShapeStyle $style)
/**
* Write polyline.
- *
- * @param \PhpOffice\Common\XMLWriter $xmlWriter
- * @param \PhpOffice\PhpWord\Style\Shape $style
*/
- private function writePolyline(XMLWriter $xmlWriter, ShapeStyle $style)
+ private function writePolyline(XMLWriter $xmlWriter, ShapeStyle $style): void
{
$xmlWriter->writeAttributeIf($style->getPoints() !== null, 'points', $style->getPoints());
}
/**
* Write rectangle.
- *
- * @param \PhpOffice\Common\XMLWriter $xmlWriter
- * @param \PhpOffice\PhpWord\Style\Shape $style
*/
- private function writeRoundRect(XMLWriter $xmlWriter, ShapeStyle $style)
+ private function writeRoundRect(XMLWriter $xmlWriter, ShapeStyle $style): void
{
$xmlWriter->writeAttribute('arcsize', $style->getRoundness());
}
/**
- * Set points
+ * Set points.
*
* @param string $type
* @param string $value
+ *
* @return array
*/
private function getPoints($type, $value)
{
- $points = array();
+ $points = [];
switch ($type) {
case 'arc':
case 'line':
$points = explode(' ', $value);
- list($start, $end) = array_pad($points, 2, null);
- $points = array('start' => $start, 'end' => $end);
+ [$start, $end] = array_pad($points, 2, null);
+ $points = ['start' => $start, 'end' => $end];
+
break;
case 'curve':
$points = explode(' ', $value);
- list($start, $end, $point1, $point2) = array_pad($points, 4, null);
- $points = array('start' => $start, 'end' => $end, 'point1' => $point1, 'point2' => $point2);
+ [$start, $end, $point1, $point2] = array_pad($points, 4, null);
+ $points = ['start' => $start, 'end' => $end, 'point1' => $point1, 'point2' => $point2];
+
break;
}
diff --git a/src/PhpWord/Writer/Word2007/Element/TOC.php b/src/PhpWord/Writer/Word2007/Element/TOC.php
index 94437cbf0d..44c6ba11fa 100644
--- a/src/PhpWord/Writer/Word2007/Element/TOC.php
+++ b/src/PhpWord/Writer/Word2007/Element/TOC.php
@@ -1,4 +1,5 @@
getXmlWriter();
$element = $this->getElement();
@@ -62,20 +64,15 @@ public function write()
}
/**
- * Write title
- *
- * @param \PhpOffice\Common\XMLWriter $xmlWriter
- * @param \PhpOffice\PhpWord\Element\TOC $element
- * @param \PhpOffice\PhpWord\Element\Title $title
- * @param bool $writeFieldMark
+ * Write title.
*/
- private function writeTitle(XMLWriter $xmlWriter, TOCElement $element, $title, $writeFieldMark)
+ private function writeTitle(XMLWriter $xmlWriter, TOCElement $element, Title $title, bool $writeFieldMark): void
{
$tocStyle = $element->getStyleTOC();
$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');
@@ -97,7 +94,10 @@ private function writeTitle(XMLWriter $xmlWriter, TOCElement $element, $title, $
$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
@@ -114,10 +114,24 @@ private function writeTitle(XMLWriter $xmlWriter, TOCElement $element, $title, $
$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();
+ 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');
@@ -130,13 +144,9 @@ private function writeTitle(XMLWriter $xmlWriter, TOCElement $element, $title, $
}
/**
- * Write style
- *
- * @param \PhpOffice\Common\XMLWriter $xmlWriter
- * @param \PhpOffice\PhpWord\Element\TOC $element
- * @param int $indent
+ * Write style.
*/
- private function writeStyle(XMLWriter $xmlWriter, TOCElement $element, $indent)
+ private function writeStyle(XMLWriter $xmlWriter, TOCElement $element, int $indent): void
{
$tocStyle = $element->getStyleTOC();
$fontStyle = $element->getStyleFont();
@@ -145,7 +155,7 @@ private function writeStyle(XMLWriter $xmlWriter, TOCElement $element, $indent)
$xmlWriter->startElement('w:pPr');
// Paragraph
- if ($isObject && !is_null($fontStyle->getParagraph())) {
+ if ($isObject && null !== $fontStyle->getParagraph()) {
$styleWriter = new ParagraphStyleWriter($xmlWriter, $fontStyle->getParagraph());
$styleWriter->write();
}
@@ -177,11 +187,8 @@ private function writeStyle(XMLWriter $xmlWriter, TOCElement $element, $indent)
/**
* Write TOC Field.
- *
- * @param \PhpOffice\Common\XMLWriter $xmlWriter
- * @param \PhpOffice\PhpWord\Element\TOC $element
*/
- private function writeFieldMark(XMLWriter $xmlWriter, TOCElement $element)
+ private function writeFieldMark(XMLWriter $xmlWriter, TOCElement $element): void
{
$minDepth = $element->getMinDepth();
$maxDepth = $element->getMaxDepth();
@@ -195,7 +202,7 @@ private function writeFieldMark(XMLWriter $xmlWriter, TOCElement $element)
$xmlWriter->startElement('w:r');
$xmlWriter->startElement('w:instrText');
$xmlWriter->writeAttribute('xml:space', 'preserve');
- $xmlWriter->text("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/Table.php b/src/PhpWord/Writer/Word2007/Element/Table.php
index c365b028ab..2bb1b3f3a8 100644
--- a/src/PhpWord/Writer/Word2007/Element/Table.php
+++ b/src/PhpWord/Writer/Word2007/Element/Table.php
@@ -1,4 +1,5 @@
getXmlWriter();
$element = $this->getElement();
@@ -60,7 +61,7 @@ public function write()
$styleWriter->write();
// Write rows
- for ($i = 0; $i < $rowCount; $i++) {
+ for ($i = 0; $i < $rowCount; ++$i) {
$this->writeRow($xmlWriter, $rows[$i]);
}
@@ -70,11 +71,8 @@ public function write()
/**
* Write column.
- *
- * @param \PhpOffice\Common\XMLWriter $xmlWriter
- * @param \PhpOffice\PhpWord\Element\Table $element
*/
- private function writeColumns(XMLWriter $xmlWriter, TableElement $element)
+ private function writeColumns(XMLWriter $xmlWriter, TableElement $element): void
{
$cellWidths = $element->findFirstDefinedCellWidths();
@@ -92,11 +90,8 @@ private function writeColumns(XMLWriter $xmlWriter, TableElement $element)
/**
* Write row.
- *
- * @param \PhpOffice\Common\XMLWriter $xmlWriter
- * @param \PhpOffice\PhpWord\Element\Row $row
*/
- private function writeRow(XMLWriter $xmlWriter, RowElement $row)
+ private function writeRow(XMLWriter $xmlWriter, RowElement $row): void
{
$xmlWriter->startElement('w:tr');
@@ -109,8 +104,14 @@ private function writeRow(XMLWriter $xmlWriter, RowElement $row)
}
// 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
@@ -118,11 +119,8 @@ private function writeRow(XMLWriter $xmlWriter, RowElement $row)
/**
* Write cell.
- *
- * @param \PhpOffice\Common\XMLWriter $xmlWriter
- * @param \PhpOffice\PhpWord\Element\Cell $cell
*/
- private function writeCell(XMLWriter $xmlWriter, CellElement $cell)
+ private function writeCell(XMLWriter $xmlWriter, CellElement $cell): void
{
$xmlWriter->startElement('w:tc');
diff --git a/src/PhpWord/Writer/Word2007/Element/TableAlignment.php b/src/PhpWord/Writer/Word2007/Element/TableAlignment.php
index f44e9ebe42..9c0977b8fd 100644
--- a/src/PhpWord/Writer/Word2007/Element/TableAlignment.php
+++ b/src/PhpWord/Writer/Word2007/Element/TableAlignment.php
@@ -1,4 +1,5 @@
getXmlWriter();
$element = $this->getElement();
@@ -64,9 +65,9 @@ public function write()
}
/**
- * Write opening of changed element
+ * Write opening of changed element.
*/
- protected function writeOpeningTrackChange()
+ protected function writeOpeningTrackChange(): void
{
$changed = $this->getElement()->getTrackChange();
if ($changed == null) {
@@ -88,9 +89,9 @@ protected function writeOpeningTrackChange()
}
/**
- * Write ending
+ * Write ending.
*/
- protected function writeClosingTrackChange()
+ protected function writeClosingTrackChange(): void
{
$changed = $this->getElement()->getTrackChange();
if ($changed == null) {
diff --git a/src/PhpWord/Writer/Word2007/Element/TextBox.php b/src/PhpWord/Writer/Word2007/Element/TextBox.php
index 9dd4bc3e57..79011d8d6f 100644
--- a/src/PhpWord/Writer/Word2007/Element/TextBox.php
+++ b/src/PhpWord/Writer/Word2007/Element/TextBox.php
@@ -1,17 +1,16 @@
getXmlWriter();
$element = $this->getElement();
@@ -50,6 +49,17 @@ public function write()
$xmlWriter->startElement('v:shape');
$xmlWriter->writeAttribute('type', '#_x0000_t0202');
+ 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();
$styleWriter->writeBorder();
diff --git a/src/PhpWord/Writer/Word2007/Element/TextBreak.php b/src/PhpWord/Writer/Word2007/Element/TextBreak.php
index 7b3d999706..4c2ecde7ed 100644
--- a/src/PhpWord/Writer/Word2007/Element/TextBreak.php
+++ b/src/PhpWord/Writer/Word2007/Element/TextBreak.php
@@ -1,4 +1,5 @@
getXmlWriter();
$element = $this->getElement();
diff --git a/src/PhpWord/Writer/Word2007/Element/TextRun.php b/src/PhpWord/Writer/Word2007/Element/TextRun.php
index e46ad3f527..865ceb742a 100644
--- a/src/PhpWord/Writer/Word2007/Element/TextRun.php
+++ b/src/PhpWord/Writer/Word2007/Element/TextRun.php
@@ -1,4 +1,5 @@
getXmlWriter();
$element = $this->getElement();
diff --git a/src/PhpWord/Writer/Word2007/Element/Title.php b/src/PhpWord/Writer/Word2007/Element/Title.php
index 6a05a34d6f..b69fbd40db 100644
--- a/src/PhpWord/Writer/Word2007/Element/Title.php
+++ b/src/PhpWord/Writer/Word2007/Element/Title.php
@@ -1,4 +1,5 @@
getXmlWriter();
$element = $this->getElement();
@@ -67,7 +68,8 @@ public function write()
$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/Word2007/Part/AbstractPart.php b/src/PhpWord/Writer/Word2007/Part/AbstractPart.php
index ce4e41cbd4..92ef1b521f 100644
--- a/src/PhpWord/Writer/Word2007/Part/AbstractPart.php
+++ b/src/PhpWord/Writer/Word2007/Part/AbstractPart.php
@@ -1,4 +1,5 @@
parentWriter = $writer;
}
/**
- * Get parent writer
+ * Get parent writer.
*
- * @throws \PhpOffice\PhpWord\Exception\Exception
- * @return \PhpOffice\PhpWord\Writer\AbstractWriter
+ * @return AbstractWriter
*/
public function getParentWriter()
{
- if (!is_null($this->parentWriter)) {
+ if (null !== $this->parentWriter) {
return $this->parentWriter;
}
+
throw new Exception('No parent WriterInterface assigned.');
}
/**
- * Get XML Writer
+ * Get XML Writer.
*
- * @return \PhpOffice\Common\XMLWriter
+ * @return XMLWriter
*/
protected function getXmlWriter()
{
$useDiskCaching = false;
- if (!is_null($this->parentWriter)) {
+ if (null !== $this->parentWriter) {
if ($this->parentWriter->isUseDiskCaching()) {
$useDiskCaching = true;
}
@@ -91,9 +90,10 @@ protected function getXmlWriter()
}
/**
- * Write an XML text, this will call text() or writeRaw() depending on the value of Settings::isOutputEscapingEnabled()
+ * 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)
diff --git a/src/PhpWord/Writer/Word2007/Part/Chart.php b/src/PhpWord/Writer/Word2007/Part/Chart.php
index 812d3bf1e3..65e686ebad 100644
--- a/src/PhpWord/Writer/Word2007/Part/Chart.php
+++ b/src/PhpWord/Writer/Word2007/Part/Chart.php
@@ -1,4 +1,5 @@
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),
- );
+ private $types = [
+ 'pie' => ['type' => 'pie', 'colors' => 1],
+ 'doughnut' => ['type' => 'doughnut', 'colors' => 1, 'hole' => 75, 'no3d' => true],
+ 'bar' => ['type' => 'bar', 'colors' => 0, 'axes' => true, 'bar' => 'bar', 'grouping' => 'clustered'],
+ 'stacked_bar' => ['type' => 'bar', 'colors' => 0, 'axes' => true, 'bar' => 'bar', 'grouping' => 'stacked'],
+ 'percent_stacked_bar' => ['type' => 'bar', 'colors' => 0, 'axes' => true, 'bar' => 'bar', 'grouping' => 'percentStacked'],
+ 'column' => ['type' => 'bar', 'colors' => 0, 'axes' => true, 'bar' => 'col', 'grouping' => 'clustered'],
+ 'stacked_column' => ['type' => 'bar', 'colors' => 0, 'axes' => true, 'bar' => 'col', 'grouping' => 'stacked'],
+ 'percent_stacked_column' => ['type' => 'bar', 'colors' => 0, 'axes' => true, 'bar' => 'col', 'grouping' => 'percentStacked'],
+ 'line' => ['type' => 'line', 'colors' => 0, 'axes' => true],
+ 'area' => ['type' => 'area', 'colors' => 0, 'axes' => true],
+ 'radar' => ['type' => 'radar', 'colors' => 0, 'axes' => true, 'radar' => 'standard', 'no3d' => true],
+ 'scatter' => ['type' => 'scatter', 'colors' => 0, 'axes' => true, 'scatter' => 'marker', 'no3d' => true],
+ ];
/**
- * Chart options
+ * Chart options.
*
* @var array
*/
- private $options = array();
+ private $options = [];
/**
* Set chart element.
- *
- * @param \PhpOffice\PhpWord\Element\Chart $element
*/
- public function setElement(ChartElement $element)
+ public function setElement(ChartElement $element): void
{
$this->element = $element;
}
/**
- * Write part
+ * Write part.
*
* @return string
*/
@@ -96,12 +95,11 @@ public function write()
}
/**
- * Write chart
+ * Write chart.
*
* @see http://www.datypic.com/sc/ooxml/t-draw-chart_CT_Chart.html
- * @param \PhpOffice\Common\XMLWriter $xmlWriter
*/
- private function writeChart(XMLWriter $xmlWriter)
+ private function writeChart(XMLWriter $xmlWriter): void
{
$xmlWriter->startElement('c:chart');
@@ -121,9 +119,8 @@ 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
*/
- private function writePlotArea(XMLWriter $xmlWriter)
+ private function writePlotArea(XMLWriter $xmlWriter): void
{
$type = $this->element->getType();
$style = $this->element->getStyle();
@@ -131,6 +128,7 @@ private function writePlotArea(XMLWriter $xmlWriter)
$title = $style->getTitle();
$showLegend = $style->isShowLegend();
+ $legendPosition = $style->getLegendPosition();
//Chart title
if ($title) {
@@ -154,7 +152,7 @@ private function writePlotArea(XMLWriter $xmlWriter)
//Chart legend
if ($showLegend) {
- $xmlWriter->writeRaw('
');
+ $xmlWriter->writeRaw('
');
}
$xmlWriter->startElement('c:plotArea');
@@ -187,7 +185,10 @@ private function writePlotArea(XMLWriter $xmlWriter)
// Series
$this->writeSeries($xmlWriter, isset($this->options['scatter']));
- $xmlWriter->writeElementBlock('c:overlap', 'val', '100');
+ // don't overlap if grouping is 'clustered'
+ if (!isset($this->options['grouping']) || $this->options['grouping'] != 'clustered') {
+ $xmlWriter->writeElementBlock('c:overlap', 'val', '100');
+ }
// Axes
if (isset($this->options['axes'])) {
@@ -209,16 +210,16 @@ private function writePlotArea(XMLWriter $xmlWriter)
/**
* Write series.
*
- * @param \PhpOffice\Common\XMLWriter $xmlWriter
* @param bool $scatter
*/
- private function writeSeries(XMLWriter $xmlWriter, $scatter = false)
+ private function writeSeries(XMLWriter $xmlWriter, $scatter = false): void
{
$series = $this->element->getSeries();
$style = $this->element->getStyle();
$colors = $style->getColors();
$index = 0;
+ $colorIndex = 0;
foreach ($series as $seriesItem) {
$categories = $seriesItem['categories'];
$values = $seriesItem['values'];
@@ -228,7 +229,7 @@ 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'] != '') {
+ if (null !== $seriesItem['name'] && $seriesItem['name'] != '') {
$xmlWriter->startElement('c:tx');
$xmlWriter->startElement('c:strRef');
$xmlWriter->startElement('c:strCache');
@@ -265,48 +266,45 @@ 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;
+ for ($i = 0; $i < count($values); ++$i) {
+ // 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;
}
}
}
$xmlWriter->endElement(); // c:ser
- $index++;
+ ++$index;
}
}
/**
* Write series items.
*
- * @param \PhpOffice\Common\XMLWriter $xmlWriter
* @param string $type
* @param array $values
*/
- private function writeSeriesItem(XMLWriter $xmlWriter, $type, $values)
+ private function writeSeriesItem(XMLWriter $xmlWriter, $type, $values): void
{
- $types = array(
- 'cat' => array('c:cat', 'c:strLit'),
- 'val' => array('c:val', 'c:numLit'),
- 'xVal' => array('c:xVal', 'c:strLit'),
- 'yVal' => array('c:yVal', 'c:numLit'),
- );
- list($itemType, $itemLit) = $types[$type];
+ $types = [
+ 'cat' => ['c:cat', 'c:strLit'],
+ 'val' => ['c:val', 'c:numLit'],
+ 'xVal' => ['c:xVal', 'c:strLit'],
+ 'yVal' => ['c:yVal', 'c:numLit'],
+ ];
+ [$itemType, $itemLit] = $types[$type];
$xmlWriter->startElement($itemType);
$xmlWriter->startElement($itemLit);
@@ -324,7 +322,7 @@ private function writeSeriesItem(XMLWriter $xmlWriter, $type, $values)
$xmlWriter->endElement(); // c:v
}
$xmlWriter->endElement(); // c:pt
- $index++;
+ ++$index;
}
$xmlWriter->endElement(); // $itemLit
@@ -332,20 +330,20 @@ private function writeSeriesItem(XMLWriter $xmlWriter, $type, $values)
}
/**
- * Write axis
+ * Write axis.
*
* @see http://www.datypic.com/sc/ooxml/t-draw-chart_CT_CatAx.html
- * @param \PhpOffice\Common\XMLWriter $xmlWriter
+ *
* @param string $type
*/
- private function writeAxis(XMLWriter $xmlWriter, $type)
+ private function writeAxis(XMLWriter $xmlWriter, $type): void
{
$style = $this->element->getStyle();
- $types = array(
- 'cat' => array('c:catAx', 1, 'b', 2),
- 'val' => array('c:valAx', 2, 'l', 1),
- );
- list($axisType, $axisId, $axisPos, $axisCross) = $types[$type];
+ $types = [
+ 'cat' => ['c:catAx', 1, 'b', 2],
+ 'val' => ['c:valAx', 2, 'l', 1],
+ ];
+ [$axisType, $axisId, $axisPos, $axisCross] = $types[$type];
$xmlWriter->startElement($axisType);
@@ -356,11 +354,11 @@ private function writeAxis(XMLWriter $xmlWriter, $type)
$valueAxisTitle = $style->getValueAxisTitle();
if ($axisType == 'c:catAx') {
- if (!is_null($categoryAxisTitle)) {
+ if (null !== $categoryAxisTitle) {
$this->writeAxisTitle($xmlWriter, $categoryAxisTitle);
}
} elseif ($axisType == 'c:valAx') {
- if (!is_null($valueAxisTitle)) {
+ if (null !== $valueAxisTitle) {
$this->writeAxisTitle($xmlWriter, $valueAxisTitle);
}
}
@@ -397,13 +395,13 @@ private function writeAxis(XMLWriter $xmlWriter, $type)
}
/**
- * Write shape
+ * Write shape.
*
* @see http://www.datypic.com/sc/ooxml/t-a_CT_ShapeProperties.html
- * @param \PhpOffice\Common\XMLWriter $xmlWriter
+ *
* @param bool $line
*/
- private function writeShape(XMLWriter $xmlWriter, $line = false)
+ private function writeShape(XMLWriter $xmlWriter, $line = false): void
{
$xmlWriter->startElement('c:spPr');
$xmlWriter->startElement('a:ln');
@@ -416,7 +414,7 @@ private function writeShape(XMLWriter $xmlWriter, $line = false)
$xmlWriter->endElement(); // c:spPr
}
- private function writeAxisTitle(XMLWriter $xmlWriter, $title)
+ private function writeAxisTitle(XMLWriter $xmlWriter, $title): void
{
$xmlWriter->startElement('c:title'); //start c:title
$xmlWriter->startElement('c:tx'); //start c:tx
diff --git a/src/PhpWord/Writer/Word2007/Part/Comments.php b/src/PhpWord/Writer/Word2007/Part/Comments.php
index 33c9f59e6a..e1d7d05340 100644
--- a/src/PhpWord/Writer/Word2007/Part/Comments.php
+++ b/src/PhpWord/Writer/Word2007/Part/Comments.php
@@ -1,4 +1,5 @@
startElement('w:comment');
$xmlWriter->writeAttribute('w:id', $comment->getElementId());
@@ -90,9 +88,10 @@ protected function writeComment(XMLWriter $xmlWriter, Comment $comment)
}
/**
- * Set element
+ * Set element.
+ *
+ * @param Comment[] $elements
*
- * @param \PhpOffice\PhpWord\Element\Comment[] $elements
* @return self
*/
public function setElements($elements)
diff --git a/src/PhpWord/Writer/Word2007/Part/ContentTypes.php b/src/PhpWord/Writer/Word2007/Part/ContentTypes.php
index 28a2d29449..2973eea15b 100644
--- a/src/PhpWord/Writer/Word2007/Part/ContentTypes.php
+++ b/src/PhpWord/Writer/Word2007/Part/ContentTypes.php
@@ -1,4 +1,5 @@
$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',
+ $overrides = [
+ '/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/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'];
if (!empty($contentTypes['override'])) {
@@ -78,13 +79,13 @@ public function write()
}
/**
- * Write content types element
+ * Write content types element.
*
- * @param \PhpOffice\Common\XMLWriter $xmlWriter XML Writer
+ * @param XMLWriter $xmlWriter XML Writer
* @param array $parts
* @param bool $isDefault
*/
- private function writeContentType(XMLWriter $xmlWriter, $parts, $isDefault)
+ private function writeContentType(XMLWriter $xmlWriter, $parts, $isDefault): void
{
foreach ($parts as $partName => $contentType) {
$partType = $isDefault ? 'Default' : 'Override';
diff --git a/src/PhpWord/Writer/Word2007/Part/DocPropsApp.php b/src/PhpWord/Writer/Word2007/Part/DocPropsApp.php
index 3452d86496..aaba2fcf37 100644
--- a/src/PhpWord/Writer/Word2007/Part/DocPropsApp.php
+++ b/src/PhpWord/Writer/Word2007/Part/DocPropsApp.php
@@ -1,4 +1,5 @@
writeElement('vt:i4', $propertyValue);
+
break;
case 'f':
$xmlWriter->writeElement('vt:r8', $propertyValue);
+
break;
case 'b':
$xmlWriter->writeElement('vt:bool', ($propertyValue) ? 'true' : 'false');
+
break;
case 'd':
- if ($propertyValue instanceof \DateTime) {
+ 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);
+
break;
}
$xmlWriter->endElement(); // property
diff --git a/src/PhpWord/Writer/Word2007/Part/Document.php b/src/PhpWord/Writer/Word2007/Part/Document.php
index 986b498570..9a2ec09ef2 100644
--- a/src/PhpWord/Writer/Word2007/Part/Document.php
+++ b/src/PhpWord/Writer/Word2007/Part/Document.php
@@ -1,4 +1,5 @@
0) {
foreach ($sections as $section) {
- $currentSection++;
+ ++$currentSection;
$containerWriter = new Container($xmlWriter, $section);
$containerWriter->write();
@@ -79,11 +80,8 @@ public function write()
/**
* Write begin section.
- *
- * @param \PhpOffice\Common\XMLWriter $xmlWriter
- * @param \PhpOffice\PhpWord\Element\Section $section
*/
- private function writeSection(XMLWriter $xmlWriter, Section $section)
+ private function writeSection(XMLWriter $xmlWriter, Section $section): void
{
$xmlWriter->startElement('w:p');
$xmlWriter->startElement('w:pPr');
@@ -94,11 +92,8 @@ private function writeSection(XMLWriter $xmlWriter, Section $section)
/**
* Write end section.
- *
- * @param \PhpOffice\Common\XMLWriter $xmlWriter
- * @param \PhpOffice\PhpWord\Element\Section $section
*/
- private function writeSectionSettings(XMLWriter $xmlWriter, Section $section)
+ private function writeSectionSettings(XMLWriter $xmlWriter, Section $section): void
{
$xmlWriter->startElement('w:sectPr');
@@ -126,27 +121,27 @@ private function writeSectionSettings(XMLWriter $xmlWriter, Section $section)
$xmlWriter->endElement();
}
- //footnote properties
- if ($section->getFootnotePropoperties() !== null) {
+ // Footnote properties
+ if ($section->getFootnoteProperties() !== null) {
$xmlWriter->startElement('w:footnotePr');
- if ($section->getFootnotePropoperties()->getPos() != null) {
+ if ($section->getFootnoteProperties()->getPos() != null) {
$xmlWriter->startElement('w:pos');
- $xmlWriter->writeAttribute('w:val', $section->getFootnotePropoperties()->getPos());
+ $xmlWriter->writeAttribute('w:val', $section->getFootnoteProperties()->getPos());
$xmlWriter->endElement();
}
- if ($section->getFootnotePropoperties()->getNumFmt() != null) {
+ if ($section->getFootnoteProperties()->getNumFmt() != null) {
$xmlWriter->startElement('w:numFmt');
- $xmlWriter->writeAttribute('w:val', $section->getFootnotePropoperties()->getNumFmt());
+ $xmlWriter->writeAttribute('w:val', $section->getFootnoteProperties()->getNumFmt());
$xmlWriter->endElement();
}
- if ($section->getFootnotePropoperties()->getNumStart() != null) {
+ if ($section->getFootnoteProperties()->getNumStart() != null) {
$xmlWriter->startElement('w:numStart');
- $xmlWriter->writeAttribute('w:val', $section->getFootnotePropoperties()->getNumStart());
+ $xmlWriter->writeAttribute('w:val', $section->getFootnoteProperties()->getNumStart());
$xmlWriter->endElement();
}
- if ($section->getFootnotePropoperties()->getNumRestart() != null) {
+ if ($section->getFootnoteProperties()->getNumRestart() != null) {
$xmlWriter->startElement('w:numRestart');
- $xmlWriter->writeAttribute('w:val', $section->getFootnotePropoperties()->getNumRestart());
+ $xmlWriter->writeAttribute('w:val', $section->getFootnoteProperties()->getNumRestart());
$xmlWriter->endElement();
}
$xmlWriter->endElement();
diff --git a/src/PhpWord/Writer/Word2007/Part/Endnotes.php b/src/PhpWord/Writer/Word2007/Part/Endnotes.php
index ce3a46bfb7..5e733834db 100644
--- a/src/PhpWord/Writer/Word2007/Part/Endnotes.php
+++ b/src/PhpWord/Writer/Word2007/Part/Endnotes.php
@@ -1,4 +1,5 @@
';
$str .= '';
+ $str .= '
';
+ $str .= ' ';
+ $str .= ' ';
+ $str .= ' ';
+ $str .= ' ';
+ $str .= ' ';
+ $str .= ' ';
+
$str .= '';
return $str;
diff --git a/src/PhpWord/Writer/Word2007/Part/Footer.php b/src/PhpWord/Writer/Word2007/Part/Footer.php
index 97b4779042..0e2f55e74e 100644
--- a/src/PhpWord/Writer/Word2007/Part/Footer.php
+++ b/src/PhpWord/Writer/Word2007/Part/Footer.php
@@ -1,4 +1,5 @@
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/src/PhpWord/Writer/Word2007/Part/Header.php b/src/PhpWord/Writer/Word2007/Part/Header.php
index b58df1f9df..1fafc79129 100644
--- a/src/PhpWord/Writer/Word2007/Part/Header.php
+++ b/src/PhpWord/Writer/Word2007/Part/Header.php
@@ -1,4 +1,5 @@
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
}
@@ -96,29 +95,26 @@ public function write()
/**
* Write level.
- *
- * @param \PhpOffice\Common\XMLWriter $xmlWriter
- * @param \PhpOffice\PhpWord\Style\NumberingLevel $level
*/
- private function writeLevel(XMLWriter $xmlWriter, NumberingLevel $level)
+ private function writeLevel(XMLWriter $xmlWriter, NumberingLevel $level): void
{
$xmlWriter->startElement('w:lvl');
$xmlWriter->writeAttribute('w:ilvl', $level->getLevel());
// Numbering level properties
- $properties = array(
- 'start' => 'start',
- 'format' => 'numFmt',
- 'restart' => 'lvlRestart',
- 'pStyle' => 'pStyle',
- 'suffix' => 'suff',
- 'text' => 'lvlText',
+ $properties = [
+ 'start' => 'start',
+ 'format' => 'numFmt',
+ 'restart' => 'lvlRestart',
+ 'pStyle' => 'pStyle',
+ 'suffix' => 'suff',
+ 'text' => 'lvlText',
'alignment' => 'lvlJc',
- );
+ ];
foreach ($properties as $property => $nodeName) {
$getMethod = "get{$property}";
if ('' !== $level->$getMethod() // this condition is now supported by `alignment` only
- && !is_null($level->$getMethod())) {
+ && null !== $level->$getMethod()) {
$xmlWriter->startElement("w:{$nodeName}");
$xmlWriter->writeAttribute('w:val', $level->$getMethod());
$xmlWriter->endElement(); // w:start
@@ -137,11 +133,9 @@ private function writeLevel(XMLWriter $xmlWriter, NumberingLevel $level)
*
* @since 0.11.0
*
- * @param \PhpOffice\Common\XMLWriter $xmlWriter
- * @param \PhpOffice\PhpWord\Style\NumberingLevel $level
* @todo Use paragraph style writer
*/
- private function writeParagraph(XMLWriter $xmlWriter, NumberingLevel $level)
+ private function writeParagraph(XMLWriter $xmlWriter, NumberingLevel $level): void
{
$tabPos = $level->getTabPos();
$left = $level->getLeft();
@@ -169,11 +163,9 @@ private function writeParagraph(XMLWriter $xmlWriter, NumberingLevel $level)
*
* @since 0.11.0
*
- * @param \PhpOffice\Common\XMLWriter $xmlWriter
- * @param \PhpOffice\PhpWord\Style\NumberingLevel $level
* @todo Use font style writer
*/
- private function writeFont(XMLWriter $xmlWriter, NumberingLevel $level)
+ private function writeFont(XMLWriter $xmlWriter, NumberingLevel $level): void
{
$font = $level->getFont();
$hint = $level->getHint();
@@ -189,13 +181,14 @@ private function writeFont(XMLWriter $xmlWriter, NumberingLevel $level)
}
/**
- * Get random hexadecimal number value
+ * Get random hexadecimal number value.
*
* @param int $length
+ *
* @return string
*/
private function getRandomHexNumber($length = 8)
{
- return strtoupper(substr(md5(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 661a4fa862..f282f80ef4 100644
--- a/src/PhpWord/Writer/Word2007/Part/Rels.php
+++ b/src/PhpWord/Writer/Word2007/Part/Rels.php
@@ -1,4 +1,5 @@
'package/2006/relationships/metadata/core-properties',
- 'docProps/app.xml' => 'officeDocument/2006/relationships/extended-properties',
+ $xmlRels = [
+ 'docProps/core.xml' => 'package/2006/relationships/metadata/core-properties',
+ 'docProps/app.xml' => 'officeDocument/2006/relationships/extended-properties',
'docProps/custom.xml' => 'officeDocument/2006/relationships/custom-properties',
- 'word/document.xml' => 'officeDocument/2006/relationships/officeDocument',
- );
+ 'word/document.xml' => 'officeDocument/2006/relationships/officeDocument',
+ ];
$xmlWriter = $this->getXmlWriter();
$this->writeRels($xmlWriter, $xmlRels);
@@ -49,12 +50,11 @@ public function write()
/**
* Write relationships.
*
- * @param \PhpOffice\Common\XMLWriter $xmlWriter
* @param array $xmlRels
* @param array $mediaRels
* @param int $relId
*/
- protected function writeRels(XMLWriter $xmlWriter, $xmlRels = array(), $mediaRels = array(), $relId = 1)
+ protected function writeRels(XMLWriter $xmlWriter, $xmlRels = [], $mediaRels = [], $relId = 1): void
{
$xmlWriter->startDocument('1.0', 'UTF-8', 'yes');
$xmlWriter->startElement('Relationships');
@@ -76,19 +76,18 @@ protected function writeRels(XMLWriter $xmlWriter, $xmlRels = array(), $mediaRel
/**
* Write media relationships.
*
- * @param \PhpOffice\Common\XMLWriter $xmlWriter
* @param int $relId
* @param array $mediaRel
*/
- private function writeMediaRel(XMLWriter $xmlWriter, $relId, $mediaRel)
+ private function writeMediaRel(XMLWriter $xmlWriter, $relId, $mediaRel): void
{
$typePrefix = 'officeDocument/2006/relationships/';
- $typeMapping = array('image' => 'image', 'object' => 'oleObject', 'link' => 'hyperlink');
- $targetMapping = array('image' => 'media/', 'object' => 'embeddings/');
+ $typeMapping = ['image' => 'image', 'object' => 'oleObject', 'link' => 'hyperlink'];
+ $targetMapping = ['image' => 'media/', 'object' => 'embeddings/'];
$mediaType = $mediaRel['type'];
- $type = isset($typeMapping[$mediaType]) ? $typeMapping[$mediaType] : $mediaType;
- $targetPrefix = isset($targetMapping[$mediaType]) ? $targetMapping[$mediaType] : '';
+ $type = $typeMapping[$mediaType] ?? $mediaType;
+ $targetPrefix = $targetMapping[$mediaType] ?? '';
$target = $mediaRel['target'];
$targetMode = ($type == 'hyperlink') ? 'External' : '';
@@ -101,15 +100,12 @@ private function writeMediaRel(XMLWriter $xmlWriter, $relId, $mediaRel)
* Format:
*
*
- * @param \PhpOffice\Common\XMLWriter $xmlWriter
* @param int $relId Relationship ID
* @param string $type Relationship type
* @param string $target Relationship target
* @param string $targetMode Relationship target mode
- *
- * @throws \PhpOffice\PhpWord\Exception\Exception
*/
- private function writeRel(XMLWriter $xmlWriter, $relId, $type, $target, $targetMode = '')
+ private function writeRel(XMLWriter $xmlWriter, $relId, $type, $target, $targetMode = ''): void
{
if ($type != '' && $target != '') {
if (strpos($relId, 'rId') === false) {
diff --git a/src/PhpWord/Writer/Word2007/Part/RelsDocument.php b/src/PhpWord/Writer/Word2007/Part/RelsDocument.php
index 2a0c5e1117..d2a9f994a8 100644
--- a/src/PhpWord/Writer/Word2007/Part/RelsDocument.php
+++ b/src/PhpWord/Writer/Word2007/Part/RelsDocument.php
@@ -1,4 +1,5 @@
'officeDocument/2006/relationships/styles',
- 'numbering.xml' => 'officeDocument/2006/relationships/numbering',
- 'settings.xml' => 'officeDocument/2006/relationships/settings',
+ $xmlRels = [
+ 'styles.xml' => 'officeDocument/2006/relationships/styles',
+ 'numbering.xml' => 'officeDocument/2006/relationships/numbering',
+ 'settings.xml' => 'officeDocument/2006/relationships/settings',
'theme/theme1.xml' => 'officeDocument/2006/relationships/theme',
- 'webSettings.xml' => 'officeDocument/2006/relationships/webSettings',
- 'fontTable.xml' => 'officeDocument/2006/relationships/fontTable',
- );
+ 'webSettings.xml' => 'officeDocument/2006/relationships/webSettings',
+ 'fontTable.xml' => 'officeDocument/2006/relationships/fontTable',
+ ];
$xmlWriter = $this->getXmlWriter();
/** @var \PhpOffice\PhpWord\Writer\Word2007 $parentWriter Type hint */
diff --git a/src/PhpWord/Writer/Word2007/Part/RelsPart.php b/src/PhpWord/Writer/Word2007/Part/RelsPart.php
index ac61a0c2c7..5e73c1f28d 100644
--- a/src/PhpWord/Writer/Word2007/Part/RelsPart.php
+++ b/src/PhpWord/Writer/Word2007/Part/RelsPart.php
@@ -1,4 +1,5 @@
getXmlWriter();
- $this->writeRels($xmlWriter, array(), $this->media);
+ $this->writeRels($xmlWriter, [], $this->media);
return $xmlWriter->getData();
}
/**
- * Set media
+ * Set media.
*
* @param array $media
+ *
* @return self
*/
public function setMedia($media)
diff --git a/src/PhpWord/Writer/Word2007/Part/Settings.php b/src/PhpWord/Writer/Word2007/Part/Settings.php
index b764642a6a..cd7beb4e7b 100644
--- a/src/PhpWord/Writer/Word2007/Part/Settings.php
+++ b/src/PhpWord/Writer/Word2007/Part/Settings.php
@@ -1,4 +1,5 @@
writeElement($settingKey);
@@ -97,49 +98,49 @@ protected function writeSetting($xmlWriter, $settingKey, $settingValue)
/**
* Get settings.
*/
- private function getSettings()
+ private function getSettings(): void
{
/** @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: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')),
- 'm:wrapIndent' => array('@attributes' => array('m:val' => '1440')),
- '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',
+ $this->settings = [
+ 'w:defaultTabStop' => ['@attributes' => ['w:val' => '708']],
+ 'w:hyphenationZone' => ['@attributes' => ['w:val' => '425']],
+ 'w:characterSpacingControl' => ['@attributes' => ['w:val' => 'doNotCompress']],
+ 'w:decimalSymbol' => ['@attributes' => ['w:val' => $documentSettings->getDecimalSymbol()]],
+ 'w:listSeparator' => ['@attributes' => ['w:val' => ';']],
+ 'w:compat' => [],
+ 'm:mathPr' => [
+ 'm:mathFont' => ['@attributes' => ['m:val' => 'Cambria Math']],
+ 'm:brkBin' => ['@attributes' => ['m:val' => 'before']],
+ 'm:brkBinSub' => ['@attributes' => ['m:val' => '--']],
+ 'm:smallFrac' => ['@attributes' => ['m:val' => 'off']],
+ 'm:dispDef' => '',
+ 'm:lMargin' => ['@attributes' => ['m:val' => '0']],
+ 'm:rMargin' => ['@attributes' => ['m:val' => '0']],
+ 'm:defJc' => ['@attributes' => ['m:val' => 'centerGroup']],
+ 'm:wrapIndent' => ['@attributes' => ['m:val' => '1440']],
+ 'm:intLim' => ['@attributes' => ['m:val' => 'subSup']],
+ 'm:naryLim' => ['@attributes' => ['m:val' => 'undOvr']],
+ ],
+ 'w:clrSchemeMapping' => [
+ '@attributes' => [
+ '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',
- ),
- ),
- );
+ ],
+ ],
+ ];
$this->setOnOffValue('w:mirrorMargins', $documentSettings->hasMirrorMargins());
$this->setOnOffValue('w:hideSpellingErrors', $documentSettings->hasHideSpellingErrors());
@@ -151,6 +152,7 @@ private function getSettings()
$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());
@@ -163,19 +165,19 @@ private function getSettings()
}
/**
- * Adds a boolean attribute to the settings array
+ * Adds a boolean attribute to the settings array.
*
* @param string $settingName
- * @param bool|null $booleanValue
+ * @param null|bool $booleanValue
*/
- private function setOnOffValue($settingName, $booleanValue)
+ private function setOnOffValue($settingName, $booleanValue): void
{
if (!is_bool($booleanValue)) {
return;
}
$value = $booleanValue ? 'true' : 'false';
- $this->settings[$settingName] = array('@attributes' => array('w:val' => $value));
+ $this->settings[$settingName] = ['@attributes' => ['w:val' => $value]];
}
/**
@@ -183,146 +185,140 @@ private function setOnOffValue($settingName, $booleanValue)
*
* @param \PhpOffice\PhpWord\Metadata\Protection $documentProtection
*/
- private function setDocumentProtection($documentProtection)
+ private function setDocumentProtection($documentProtection): void
{
if ($documentProtection->getEditing() !== null) {
if ($documentProtection->getPassword() == null) {
- $this->settings['w:documentProtection'] = array(
- '@attributes' => array(
+ $this->settings['w:documentProtection'] = [
+ '@attributes' => [
'w:enforcement' => 1,
- 'w:edit' => $documentProtection->getEditing(),
- ),
- );
+ 'w:edit' => $documentProtection->getEditing(),
+ ],
+ ];
} 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'] = array(
- '@attributes' => array(
- 'w:enforcement' => 1,
- 'w:edit' => $documentProtection->getEditing(),
- 'w:cryptProviderType' => 'rsaFull',
+ $this->settings['w:documentProtection'] = [
+ '@attributes' => [
+ 'w:enforcement' => 1,
+ 'w:edit' => $documentProtection->getEditing(),
+ 'w:cryptProviderType' => 'rsaFull',
'w:cryptAlgorithmClass' => 'hash',
- 'w:cryptAlgorithmType' => 'typeAny',
- 'w:cryptAlgorithmSid' => PasswordEncoder::getAlgorithmId($documentProtection->getAlgorithm()),
- 'w:cryptSpinCount' => $documentProtection->getSpinCount(),
- 'w:hash' => $passwordHash,
- 'w:salt' => base64_encode($documentProtection->getSalt()),
- ),
- );
+ 'w:cryptAlgorithmType' => 'typeAny',
+ 'w:cryptAlgorithmSid' => PasswordEncoder::getAlgorithmId($documentProtection->getAlgorithm()),
+ 'w:cryptSpinCount' => $documentProtection->getSpinCount(),
+ 'w:hash' => $passwordHash,
+ 'w:salt' => base64_encode($documentProtection->getSalt()),
+ ],
+ ];
}
}
}
/**
- * Set the Proof state
- *
- * @param ProofState $proofState
+ * Set the Proof state.
*/
- private function setProofState(ProofState $proofState = null)
+ private function setProofState(?ProofState $proofState = null): void
{
if ($proofState != null && $proofState->getGrammar() !== null && $proofState->getSpelling() !== null) {
- $this->settings['w:proofState'] = array(
- '@attributes' => array(
+ $this->settings['w:proofState'] = [
+ '@attributes' => [
'w:spelling' => $proofState->getSpelling(),
- 'w:grammar' => $proofState->getGrammar(),
- ),
- );
+ 'w:grammar' => $proofState->getGrammar(),
+ ],
+ ];
}
}
/**
- * Set the Revision View
- *
- * @param TrackChangesView $trackChangesView
+ * Set the Revision View.
*/
- private function setRevisionView(TrackChangesView $trackChangesView = null)
+ private function setRevisionView(?TrackChangesView $trackChangesView = null): void
{
if ($trackChangesView != null) {
- $revisionView = array();
+ $revisionView = [];
$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);
+ $this->settings['w:revisionView'] = ['@attributes' => $revisionView];
}
}
/**
- * Sets the language
- *
- * @param Language $language
+ * Sets the language.
*/
- private function setThemeFontLang(Language $language = null)
+ private function setThemeFontLang(?Language $language = null): void
{
$latinLanguage = ($language == null || $language->getLatin() === null) ? 'en-US' : $language->getLatin();
- $lang = array();
+ $lang = [];
$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);
+ $this->settings['w:themeFontLang'] = ['@attributes' => $lang];
}
/**
- * Set the magnification
+ * Set the magnification.
*
* @param mixed $zoom
*/
- private function setZoom($zoom = null)
+ private function setZoom($zoom = null): void
{
if ($zoom !== null) {
$attr = is_int($zoom) ? 'w:percent' : 'w:val';
- $this->settings['w:zoom'] = array('@attributes' => array($attr => $zoom));
+ $this->settings['w:zoom'] = ['@attributes' => [$attr => $zoom]];
}
}
/**
- * @param int|null $consecutiveHyphenLimit
+ * @param null|int $consecutiveHyphenLimit
*/
- private function setConsecutiveHyphenLimit($consecutiveHyphenLimit)
+ private function setConsecutiveHyphenLimit($consecutiveHyphenLimit): void
{
if ($consecutiveHyphenLimit === null) {
return;
}
- $this->settings['w:consecutiveHyphenLimit'] = array(
- '@attributes' => array('w:val' => $consecutiveHyphenLimit),
- );
+ $this->settings['w:consecutiveHyphenLimit'] = [
+ '@attributes' => ['w:val' => $consecutiveHyphenLimit],
+ ];
}
/**
- * @param float|null $hyphenationZone
+ * @param null|float $hyphenationZone
*/
- private function setHyphenationZone($hyphenationZone)
+ private function setHyphenationZone($hyphenationZone): void
{
if ($hyphenationZone === null) {
return;
}
- $this->settings['w:hyphenationZone'] = array(
- '@attributes' => array('w:val' => $hyphenationZone),
- );
+ $this->settings['w:hyphenationZone'] = [
+ '@attributes' => ['w:val' => $hyphenationZone],
+ ];
}
/**
* Get compatibility setting.
*/
- private function setCompatibility()
+ private function setCompatibility(): void
{
$compatibility = $this->getParentWriter()->getPhpWord()->getCompatibility();
if ($compatibility->getOoxmlVersion() !== null) {
- $this->settings['w:compat']['w:compatSetting'] = array(
- '@attributes' => array(
+ $this->settings['w:compat']['w:compatSetting'] = [
+ '@attributes' => [
'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(),
+ ],
+ ];
}
}
}
diff --git a/src/PhpWord/Writer/Word2007/Part/Styles.php b/src/PhpWord/Writer/Word2007/Part/Styles.php
index d05338c77d..0ed9d6b6fb 100644
--- a/src/PhpWord/Writer/Word2007/Part/Styles.php
+++ b/src/PhpWord/Writer/Word2007/Part/Styles.php
@@ -1,4 +1,5 @@
getParentWriter()->getPhpWord();
$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();
@@ -94,9 +97,12 @@ private function writeDefaultStyles(XMLWriter $xmlWriter, $styles)
$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:color');
+ $xmlWriter->writeAttribute('w:val', $fontColor);
+ $xmlWriter->endElement();
$xmlWriter->startElement('w:sz');
$xmlWriter->writeAttribute('w:val', $fontSize * 2);
$xmlWriter->endElement(); // w:sz
@@ -125,7 +131,7 @@ private function writeDefaultStyles(XMLWriter $xmlWriter, $styles)
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) {
@@ -161,16 +167,14 @@ private function writeDefaultStyles(XMLWriter $xmlWriter, $styles)
/**
* Write font style.
*
- * @param \PhpOffice\Common\XMLWriter $xmlWriter
* @param string $styleName
- * @param \PhpOffice\PhpWord\Style\Font $style
*/
- private function writeFontStyle(XMLWriter $xmlWriter, $styleName, FontStyle $style)
+ private function writeFontStyle(XMLWriter $xmlWriter, $styleName, FontStyle $style): void
{
$paragraphStyle = $style->getParagraph();
$styleType = $style->getStyleType();
$type = ($styleType == 'title') ? 'paragraph' : 'character';
- if (!is_null($paragraphStyle)) {
+ if (null !== $paragraphStyle) {
$type = 'paragraph';
}
@@ -194,7 +198,7 @@ private function writeFontStyle(XMLWriter $xmlWriter, $styleName, FontStyle $sty
$xmlWriter->startElement('w:link');
$xmlWriter->writeAttribute('w:val', $styleLink);
$xmlWriter->endElement();
- } elseif (!is_null($paragraphStyle)) {
+ } elseif (null !== $paragraphStyle) {
// if type is 'paragraph' it should have a styleId
$xmlWriter->writeAttribute('w:styleId', $styleName);
}
@@ -205,7 +209,7 @@ private function writeFontStyle(XMLWriter $xmlWriter, $styleName, FontStyle $sty
$xmlWriter->endElement();
// Parent style
- if (!is_null($paragraphStyle)) {
+ if (null !== $paragraphStyle) {
if ($paragraphStyle->getStyleName() != null) {
$xmlWriter->writeElementBlock('w:basedOn', 'w:val', $paragraphStyle->getStyleName());
} elseif ($paragraphStyle->getBasedOn() != null) {
@@ -214,7 +218,7 @@ private function writeFontStyle(XMLWriter $xmlWriter, $styleName, FontStyle $sty
}
// w:pPr
- if (!is_null($paragraphStyle)) {
+ if (null !== $paragraphStyle) {
$styleWriter = new ParagraphStyleWriter($xmlWriter, $paragraphStyle);
$styleWriter->write();
}
@@ -229,11 +233,9 @@ private function writeFontStyle(XMLWriter $xmlWriter, $styleName, FontStyle $sty
/**
* Write paragraph style.
*
- * @param \PhpOffice\Common\XMLWriter $xmlWriter
* @param string $styleName
- * @param \PhpOffice\PhpWord\Style\Paragraph $style
*/
- private function writeParagraphStyle(XMLWriter $xmlWriter, $styleName, ParagraphStyle $style)
+ private function writeParagraphStyle(XMLWriter $xmlWriter, $styleName, ParagraphStyle $style): void
{
$xmlWriter->startElement('w:style');
$xmlWriter->writeAttribute('w:type', 'paragraph');
@@ -245,11 +247,11 @@ private function writeParagraphStyle(XMLWriter $xmlWriter, $styleName, Paragraph
// Parent style
$basedOn = $style->getBasedOn();
- $xmlWriter->writeElementIf(!is_null($basedOn), 'w:basedOn', 'w:val', $basedOn);
+ $xmlWriter->writeElementIf(null !== $basedOn, 'w:basedOn', 'w:val', $basedOn);
// Next paragraph style
$next = $style->getNext();
- $xmlWriter->writeElementIf(!is_null($next), 'w:next', 'w:val', $next);
+ $xmlWriter->writeElementIf(null !== $next, 'w:next', 'w:val', $next);
// w:pPr
$styleWriter = new ParagraphStyleWriter($xmlWriter, $style);
@@ -261,11 +263,9 @@ private function writeParagraphStyle(XMLWriter $xmlWriter, $styleName, Paragraph
/**
* Write table style.
*
- * @param \PhpOffice\Common\XMLWriter $xmlWriter
* @param string $styleName
- * @param \PhpOffice\PhpWord\Style\Table $style
*/
- private function writeTableStyle(XMLWriter $xmlWriter, $styleName, TableStyle $style)
+ private function writeTableStyle(XMLWriter $xmlWriter, $styleName, TableStyle $style): void
{
$xmlWriter->startElement('w:style');
$xmlWriter->writeAttribute('w:type', 'table');
diff --git a/src/PhpWord/Writer/Word2007/Part/Theme.php b/src/PhpWord/Writer/Word2007/Part/Theme.php
index f4ef478ebf..a70c248da6 100644
--- a/src/PhpWord/Writer/Word2007/Part/Theme.php
+++ b/src/PhpWord/Writer/Word2007/Part/Theme.php
@@ -1,4 +1,5 @@
'',
- );
+ ];
$xmlWriter = $this->getXmlWriter();
diff --git a/src/PhpWord/Writer/Word2007/Style/AbstractStyle.php b/src/PhpWord/Writer/Word2007/Style/AbstractStyle.php
index fcd4aeb6cc..9a30bebf0e 100644
--- a/src/PhpWord/Writer/Word2007/Style/AbstractStyle.php
+++ b/src/PhpWord/Writer/Word2007/Style/AbstractStyle.php
@@ -1,4 +1,5 @@
567,
- Settings::UNIT_MM => 56.7,
- Settings::UNIT_INCH => 1440,
+ $factors = [
+ 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;
- if (in_array($unit, $factors) && $value != $default) {
+ if (array_key_exists($unit, $factors) && $value != $default) {
$factor = $factors[$unit];
}
@@ -106,25 +107,25 @@ protected function convertTwip($value, $default = 0)
/**
* Write child style.
*
- * @param \PhpOffice\Common\XMLWriter $xmlWriter
* @param string $name
* @param mixed $value
*/
- protected function writeChildStyle(XMLWriter $xmlWriter, $name, $value)
+ 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();
}
}
/**
- * Writes boolean as 0 or 1
+ * Writes boolean as 0 or 1.
*
* @param bool $value
+ *
* @return null|string
*/
protected function writeOnOf($value = null)
@@ -137,16 +138,17 @@ protected function writeOnOf($value = null)
}
/**
- * Assemble style array into style string
+ * Assemble style array into style string.
*
* @param array $styles
+ *
* @return string
*/
- protected function assembleStyle($styles = array())
+ protected function assembleStyle($styles = [])
{
$style = '';
foreach ($styles as $key => $value) {
- if (!is_null($value) && $value != '') {
+ if (null !== $value && $value != '') {
$style .= "{$key}:{$value}; ";
}
}
diff --git a/src/PhpWord/Writer/Word2007/Style/Cell.php b/src/PhpWord/Writer/Word2007/Style/Cell.php
index 733b7b434e..bb0d6d71b0 100644
--- a/src/PhpWord/Writer/Word2007/Style/Cell.php
+++ b/src/PhpWord/Writer/Word2007/Style/Cell.php
@@ -1,4 +1,5 @@
getStyle();
if (!$style instanceof CellStyle) {
@@ -45,8 +46,8 @@ public function write()
$xmlWriter->startElement('w:tcPr');
// Width
- if (!is_null($this->width) || !is_null($style->getWidth())) {
- $width = is_null($this->width) ? $style->getWidth() : $this->width;
+ if (null !== $this->width || null !== $style->getWidth()) {
+ $width = null === $this->width ? $style->getWidth() : $this->width;
$xmlWriter->startElement('w:tcW');
$xmlWriter->writeAttribute('w:w', $width);
@@ -54,13 +55,47 @@ public function write()
$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(!is_null($textDir), 'w:textDirection', 'w:val', $textDir);
+ $xmlWriter->writeElementIf(null !== $textDir, 'w:textDirection', 'w:val', $textDir);
// Vertical alignment
$vAlign = $style->getVAlign();
- $xmlWriter->writeElementIf(!is_null($vAlign), 'w:vAlign', 'w:val', $vAlign);
+ $xmlWriter->writeElementIf(null !== $vAlign, 'w:vAlign', 'w:val', $vAlign);
// Border
if ($style->hasBorder()) {
@@ -70,7 +105,7 @@ public function write()
$styleWriter->setSizes($style->getBorderSize());
$styleWriter->setColors($style->getBorderColor());
$styleWriter->setStyles($style->getBorderStyle());
- $styleWriter->setAttributes(array('defaultColor' => CellStyle::DEFAULT_BORDER_COLOR));
+ $styleWriter->setAttributes(['defaultColor' => CellStyle::DEFAULT_BORDER_COLOR]);
$styleWriter->write();
$xmlWriter->endElement();
@@ -78,7 +113,7 @@ public function write()
// Shading
$shading = $style->getShading();
- if (!is_null($shading)) {
+ if (null !== $shading) {
$styleWriter = new Shading($xmlWriter, $shading);
$styleWriter->write();
}
@@ -86,8 +121,9 @@ public function write()
// Colspan & rowspan
$gridSpan = $style->getGridSpan();
$vMerge = $style->getVMerge();
- $xmlWriter->writeElementIf(!is_null($gridSpan), 'w:gridSpan', 'w:val', $gridSpan);
- $xmlWriter->writeElementIf(!is_null($vMerge), 'w:vMerge', 'w:val', $vMerge);
+ $xmlWriter->writeElementIf(null !== $gridSpan, 'w:gridSpan', 'w:val', $gridSpan);
+ $xmlWriter->writeElementIf(null !== $vMerge, 'w:vMerge', 'w:val', $vMerge);
+ $xmlWriter->writeElementIf($style->getNoWrap(), 'w:noWrap');
$xmlWriter->endElement(); // w:tcPr
}
@@ -97,7 +133,7 @@ public function write()
*
* @param int $value
*/
- public function setWidth($value = null)
+ public function setWidth($value = null): void
{
$this->width = $value;
}
diff --git a/src/PhpWord/Writer/Word2007/Style/Extrusion.php b/src/PhpWord/Writer/Word2007/Style/Extrusion.php
index 193993485d..8bb9218789 100644
--- a/src/PhpWord/Writer/Word2007/Style/Extrusion.php
+++ b/src/PhpWord/Writer/Word2007/Style/Extrusion.php
@@ -1,4 +1,5 @@
getStyle();
if (!$style instanceof \PhpOffice\PhpWord\Style\Extrusion) {
diff --git a/src/PhpWord/Writer/Word2007/Style/Fill.php b/src/PhpWord/Writer/Word2007/Style/Fill.php
index 53d039742b..8e21abe395 100644
--- a/src/PhpWord/Writer/Word2007/Style/Fill.php
+++ b/src/PhpWord/Writer/Word2007/Style/Fill.php
@@ -1,4 +1,5 @@
getStyle();
if (!$style instanceof \PhpOffice\PhpWord\Style\Fill) {
diff --git a/src/PhpWord/Writer/Word2007/Style/Font.php b/src/PhpWord/Writer/Word2007/Style/Font.php
index dd4fac4f0d..623e8d5e72 100644
--- a/src/PhpWord/Writer/Word2007/Style/Font.php
+++ b/src/PhpWord/Writer/Word2007/Style/Font.php
@@ -1,4 +1,5 @@
getXmlWriter();
- $isStyleName = $this->isInline && !is_null($this->style) && is_string($this->style);
+ $isStyleName = $this->isInline && null !== $this->style && is_string($this->style);
if ($isStyleName) {
$xmlWriter->startElement('w:rPr');
$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();
@@ -53,7 +58,7 @@ public function write()
/**
* Write full style.
*/
- private function writeStyle()
+ private function writeStyle(): void
{
$style = $this->getStyle();
if (!$style instanceof \PhpOffice\PhpWord\Style\Font) {
@@ -113,8 +118,8 @@ private function writeStyle()
$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()));
@@ -139,11 +144,11 @@ 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();
- if (!is_null($shading)) {
+ if (null !== $shading) {
$styleWriter = new Shading($xmlWriter, $shading);
$styleWriter->write();
}
@@ -165,7 +170,7 @@ private function writeStyle()
*
* @param bool $value
*/
- public function setIsInline($value)
+ public function setIsInline($value): void
{
$this->isInline = $value;
}
diff --git a/src/PhpWord/Writer/Word2007/Style/Frame.php b/src/PhpWord/Writer/Word2007/Style/Frame.php
index 10e5b151f7..a7aab43e61 100644
--- a/src/PhpWord/Writer/Word2007/Style/Frame.php
+++ b/src/PhpWord/Writer/Word2007/Style/Frame.php
@@ -1,4 +1,5 @@
getStyle();
if (!$style instanceof FrameStyle) {
@@ -42,27 +43,27 @@ public function write()
$xmlWriter = $this->getXmlWriter();
$maxZIndex = min(PHP_INT_MAX, self::PHP_32BIT_INT_MAX);
- $zIndices = array(FrameStyle::WRAP_INFRONT => $maxZIndex, FrameStyle::WRAP_BEHIND => -$maxZIndex);
-
- $properties = array(
- 'width' => 'width',
- 'height' => 'height',
- 'left' => 'margin-left',
- 'top' => 'margin-top',
- 'wrapDistanceTop' => 'mso-wrap-distance-top',
+ $zIndices = [FrameStyle::WRAP_INFRONT => $maxZIndex, FrameStyle::WRAP_BEHIND => -$maxZIndex];
+
+ $properties = [
+ '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',
- );
+ 'wrapDistanceLeft' => 'mso-wrap-distance-left',
+ 'wrapDistanceRight' => 'mso-wrap-distance-right',
+ ];
$sizeStyles = $this->getStyles($style, $properties, $style->getUnit());
- $properties = array(
- 'pos' => 'position',
- 'hPos' => 'mso-position-horizontal',
- 'vPos' => 'mso-position-vertical',
+ $properties = [
+ 'pos' => 'position',
+ 'hPos' => 'mso-position-horizontal',
+ 'vPos' => 'mso-position-vertical',
'hPosRelTo' => 'mso-position-horizontal-relative',
'vPosRelTo' => 'mso-position-vertical-relative',
- );
+ ];
$posStyles = $this->getStyles($style, $properties);
$styles = array_merge($sizeStyles, $posStyles);
@@ -83,7 +84,7 @@ public function write()
/**
* Write alignment.
*/
- public function writeAlignment()
+ public function writeAlignment(): void
{
$style = $this->getStyle();
if (!$style instanceof FrameStyle) {
@@ -108,24 +109,22 @@ public function writeAlignment()
/**
* Write wrap.
*
- * @param \PhpOffice\Common\XMLWriter $xmlWriter
- * @param \PhpOffice\PhpWord\Style\Frame $style
* @param string $wrap
*/
- private function writeWrap(XMLWriter $xmlWriter, FrameStyle $style, $wrap)
+ private function writeWrap(XMLWriter $xmlWriter, FrameStyle $style, $wrap): void
{
if ($wrap !== null) {
$xmlWriter->startElement('w10:wrap');
$xmlWriter->writeAttribute('type', $wrap);
- $relativePositions = array(
- FrameStyle::POS_RELTO_MARGIN => 'margin',
- FrameStyle::POS_RELTO_PAGE => 'page',
+ $relativePositions = [
+ FrameStyle::POS_RELTO_MARGIN => 'margin',
+ FrameStyle::POS_RELTO_PAGE => 'page',
FrameStyle::POS_RELTO_TMARGIN => 'margin',
FrameStyle::POS_RELTO_BMARGIN => 'page',
FrameStyle::POS_RELTO_LMARGIN => 'margin',
FrameStyle::POS_RELTO_RMARGIN => 'page',
- );
+ ];
$pos = $style->getPos();
$hPos = $style->getHPosRelTo();
$vPos = $style->getVPosRelTo();
@@ -147,16 +146,16 @@ private function writeWrap(XMLWriter $xmlWriter, FrameStyle $style, $wrap)
}
/**
- * Get style values in associative array
+ * Get style values in associative array.
*
- * @param \PhpOffice\PhpWord\Style\Frame $style
* @param array $properties
* @param string $suffix
+ *
* @return array
*/
private function getStyles(FrameStyle $style, $properties, $suffix = '')
{
- $styles = array();
+ $styles = [];
foreach ($properties as $key => $property) {
$method = "get{$key}";
diff --git a/src/PhpWord/Writer/Word2007/Style/Image.php b/src/PhpWord/Writer/Word2007/Style/Image.php
index ef23ed103c..a2279e5b9c 100644
--- a/src/PhpWord/Writer/Word2007/Style/Image.php
+++ b/src/PhpWord/Writer/Word2007/Style/Image.php
@@ -1,4 +1,5 @@
getStyle();
if (!$style instanceof \PhpOffice\PhpWord\Style\Indentation) {
@@ -41,10 +42,13 @@ public function write()
$xmlWriter->writeAttribute('w:right', $this->convertTwip($style->getRight()));
$firstLine = $style->getFirstLine();
- $xmlWriter->writeAttributeIf(!is_null($firstLine), 'w:firstLine', $this->convertTwip($firstLine));
+ $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(!is_null($hanging), 'w:hanging', $this->convertTwip($hanging));
+ $xmlWriter->writeAttributeIf(null !== $hanging, 'w:hanging', $this->convertTwip($hanging));
$xmlWriter->endElement();
}
diff --git a/src/PhpWord/Writer/Word2007/Style/Line.php b/src/PhpWord/Writer/Word2007/Style/Line.php
index 154a42c13d..2603545fc2 100644
--- a/src/PhpWord/Writer/Word2007/Style/Line.php
+++ b/src/PhpWord/Writer/Word2007/Style/Line.php
@@ -1,4 +1,5 @@
getXmlWriter();
$style = $this->getStyle();
@@ -37,15 +39,15 @@ public function writeStroke()
}
$dash = $style->getDash();
- $dashStyles = array(
- LineStyle::DASH_STYLE_DASH => 'dash',
- LineStyle::DASH_STYLE_ROUND_DOT => '1 1',
- LineStyle::DASH_STYLE_SQUARE_DOT => '1 1',
- LineStyle::DASH_STYLE_DASH_DOT => 'dashDot',
- LineStyle::DASH_STYLE_LONG_DASH => 'longDash',
- LineStyle::DASH_STYLE_LONG_DASH_DOT => 'longDashDot',
+ $dashStyles = [
+ LineStyle::DASH_STYLE_DASH => 'dash',
+ LineStyle::DASH_STYLE_ROUND_DOT => '1 1',
+ LineStyle::DASH_STYLE_SQUARE_DOT => '1 1',
+ LineStyle::DASH_STYLE_DASH_DOT => 'dashDot',
+ LineStyle::DASH_STYLE_LONG_DASH => 'longDash',
+ LineStyle::DASH_STYLE_LONG_DASH_DOT => 'longDashDot',
LineStyle::DASH_STYLE_LONG_DASH_DOT_DOT => 'longDashDotDot',
- );
+ ];
$xmlWriter->startElement('v:stroke');
diff --git a/src/PhpWord/Writer/Word2007/Style/LineNumbering.php b/src/PhpWord/Writer/Word2007/Style/LineNumbering.php
index 4bf08b65ab..f915e3ab4e 100644
--- a/src/PhpWord/Writer/Word2007/Style/LineNumbering.php
+++ b/src/PhpWord/Writer/Word2007/Style/LineNumbering.php
@@ -1,4 +1,5 @@
getStyle();
if (!$style instanceof \PhpOffice\PhpWord\Style\LineNumbering) {
diff --git a/src/PhpWord/Writer/Word2007/Style/MarginBorder.php b/src/PhpWord/Writer/Word2007/Style/MarginBorder.php
index f5c4b0153b..b464e66ffb 100644
--- a/src/PhpWord/Writer/Word2007/Style/MarginBorder.php
+++ b/src/PhpWord/Writer/Word2007/Style/MarginBorder.php
@@ -1,4 +1,5 @@
getXmlWriter();
- $sides = array('top', 'left', 'right', 'bottom', 'insideH', 'insideV');
+ $sides = ['top', 'left', 'right', 'bottom', 'insideH', 'insideV'];
foreach ($this->sizes as $i => $size) {
if ($size !== null) {
@@ -69,7 +70,7 @@ public function write()
if (isset($this->colors[$i])) {
$color = $this->colors[$i];
}
- $style = isset($this->styles[$i]) ? $this->styles[$i] : 'single';
+ $style = $this->styles[$i] ?? 'single';
$this->writeSide($xmlWriter, $sides[$i], $this->sizes[$i], $color, $style);
}
}
@@ -78,13 +79,12 @@ public function write()
/**
* Write side.
*
- * @param \PhpOffice\Common\XMLWriter $xmlWriter
* @param string $side
* @param int $width
* @param string $color
* @param string $borderStyle
*/
- private function writeSide(XMLWriter $xmlWriter, $side, $width, $color = null, $borderStyle = 'solid')
+ private function writeSide(XMLWriter $xmlWriter, $side, $width, $color = null, $borderStyle = 'solid'): void
{
$xmlWriter->startElement('w:' . $side);
if (!empty($this->colors)) {
@@ -113,7 +113,7 @@ private function writeSide(XMLWriter $xmlWriter, $side, $width, $color = null, $
*
* @param int[] $value
*/
- public function setSizes($value)
+ public function setSizes($value): void
{
$this->sizes = $value;
}
@@ -121,9 +121,9 @@ public function setSizes($value)
/**
* Set colors.
*
- * @param string[] $value
+ * @param array
$value
*/
- public function setColors($value)
+ public function setColors($value): void
{
$this->colors = $value;
}
@@ -133,7 +133,7 @@ public function setColors($value)
*
* @param string[] $value
*/
- public function setStyles($value)
+ public function setStyles($value): void
{
$this->styles = $value;
}
@@ -143,7 +143,7 @@ public function setStyles($value)
*
* @param array $value
*/
- public function setAttributes($value)
+ public function setAttributes($value): void
{
$this->attributes = $value;
}
diff --git a/src/PhpWord/Writer/Word2007/Style/Outline.php b/src/PhpWord/Writer/Word2007/Style/Outline.php
index ae4c1da386..45f37cc61e 100644
--- a/src/PhpWord/Writer/Word2007/Style/Outline.php
+++ b/src/PhpWord/Writer/Word2007/Style/Outline.php
@@ -1,4 +1,5 @@
getStyle();
if (!$style instanceof \PhpOffice\PhpWord\Style\Outline) {
diff --git a/src/PhpWord/Writer/Word2007/Style/Paragraph.php b/src/PhpWord/Writer/Word2007/Style/Paragraph.php
index 6761608608..55f51a54d6 100644
--- a/src/PhpWord/Writer/Word2007/Style/Paragraph.php
+++ b/src/PhpWord/Writer/Word2007/Style/Paragraph.php
@@ -1,4 +1,5 @@
getXmlWriter();
- $isStyleName = $this->isInline && !is_null($this->style) && is_string($this->style);
+ $isStyleName = $this->isInline && null !== $this->style && is_string($this->style);
if ($isStyleName) {
if (!$this->withoutPPR) {
$xmlWriter->startElement('w:pPr');
@@ -69,7 +70,7 @@ public function write()
/**
* Write full style.
*/
- private function writeStyle()
+ private function writeStyle(): void
{
$style = $this->getStyle();
if (!$style instanceof ParagraphStyle) {
@@ -132,6 +133,7 @@ private function writeStyle()
$styleWriter = new MarginBorder($xmlWriter);
$styleWriter->setSizes($style->getBorderSize());
+ $styleWriter->setStyles($style->getBorderStyle());
$styleWriter->setColors($style->getBorderColor());
$styleWriter->write();
@@ -146,10 +148,9 @@ private function writeStyle()
/**
* Write tabs.
*
- * @param \PhpOffice\Common\XMLWriter $xmlWriter
- * @param \PhpOffice\PhpWord\Style\Tab[] $tabs
+ * @param Style\Tab[] $tabs
*/
- private function writeTabs(XMLWriter $xmlWriter, $tabs)
+ private function writeTabs(XMLWriter $xmlWriter, $tabs): void
{
if (!empty($tabs)) {
$xmlWriter->startElement('w:tabs');
@@ -164,15 +165,14 @@ private function writeTabs(XMLWriter $xmlWriter, $tabs)
/**
* Write numbering.
*
- * @param \PhpOffice\Common\XMLWriter $xmlWriter
* @param array $numbering
*/
- private function writeNumbering(XMLWriter $xmlWriter, $numbering)
+ 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');
@@ -195,7 +195,7 @@ private function writeNumbering(XMLWriter $xmlWriter, $numbering)
*
* @param bool $value
*/
- public function setWithoutPPR($value)
+ public function setWithoutPPR($value): void
{
$this->withoutPPR = $value;
}
@@ -205,7 +205,7 @@ public function setWithoutPPR($value)
*
* @param bool $value
*/
- public function setIsInline($value)
+ public function setIsInline($value): void
{
$this->isInline = $value;
}
diff --git a/src/PhpWord/Writer/Word2007/Style/Row.php b/src/PhpWord/Writer/Word2007/Style/Row.php
index 82028d24c4..2b9d804f39 100644
--- a/src/PhpWord/Writer/Word2007/Style/Row.php
+++ b/src/PhpWord/Writer/Word2007/Style/Row.php
@@ -1,4 +1,5 @@
getStyle();
if (!$style instanceof \PhpOffice\PhpWord\Style\Row) {
@@ -59,7 +60,7 @@ public function write()
*
* @param int $value
*/
- public function setHeight($value = null)
+ public function setHeight($value = null): void
{
$this->height = $value;
}
diff --git a/src/PhpWord/Writer/Word2007/Style/Section.php b/src/PhpWord/Writer/Word2007/Style/Section.php
index 1122b6ff76..cb2c9a083a 100644
--- a/src/PhpWord/Writer/Word2007/Style/Section.php
+++ b/src/PhpWord/Writer/Word2007/Style/Section.php
@@ -1,4 +1,5 @@
getStyle();
if (!$style instanceof SectionStyle) {
@@ -39,7 +40,7 @@ public function write()
// Break type
$breakType = $style->getBreakType();
- $xmlWriter->writeElementIf(!is_null($breakType), 'w:type', 'w:val', $breakType);
+ $xmlWriter->writeElementIf(null !== $breakType, 'w:type', 'w:val', $breakType);
// Page size & orientation
$xmlWriter->startElement('w:pgSz');
@@ -50,21 +51,21 @@ public function write()
// Vertical alignment
$vAlign = $style->getVAlign();
- $xmlWriter->writeElementIf(!is_null($vAlign), 'w:vAlign', 'w:val', $vAlign);
+ $xmlWriter->writeElementIf(null !== $vAlign, 'w:vAlign', 'w:val', $vAlign);
// Margins
- $margins = array(
- 'w:top' => array('getMarginTop', SectionStyle::DEFAULT_MARGIN),
- 'w:right' => array('getMarginRight', SectionStyle::DEFAULT_MARGIN),
- 'w:bottom' => array('getMarginBottom', SectionStyle::DEFAULT_MARGIN),
- 'w:left' => array('getMarginLeft', SectionStyle::DEFAULT_MARGIN),
- 'w:header' => array('getHeaderHeight', SectionStyle::DEFAULT_HEADER_HEIGHT),
- 'w:footer' => array('getFooterHeight', SectionStyle::DEFAULT_FOOTER_HEIGHT),
- 'w:gutter' => array('getGutter', SectionStyle::DEFAULT_GUTTER),
- );
+ $margins = [
+ 'w:top' => ['getMarginTop', SectionStyle::DEFAULT_MARGIN],
+ 'w:right' => ['getMarginRight', SectionStyle::DEFAULT_MARGIN],
+ 'w:bottom' => ['getMarginBottom', SectionStyle::DEFAULT_MARGIN],
+ 'w:left' => ['getMarginLeft', SectionStyle::DEFAULT_MARGIN],
+ 'w:header' => ['getHeaderHeight', SectionStyle::DEFAULT_HEADER_HEIGHT],
+ 'w:footer' => ['getFooterHeight', SectionStyle::DEFAULT_FOOTER_HEIGHT],
+ 'w:gutter' => ['getGutter', SectionStyle::DEFAULT_GUTTER],
+ ];
$xmlWriter->startElement('w:pgMar');
foreach ($margins as $attribute => $value) {
- list($method, $default) = $value;
+ [$method, $default] = $value;
$xmlWriter->writeAttribute($attribute, $this->convertTwip($style->$method(), $default));
}
$xmlWriter->endElement();
@@ -77,7 +78,7 @@ public function write()
$styleWriter = new MarginBorder($xmlWriter);
$styleWriter->setSizes($style->getBorderSize());
$styleWriter->setColors($style->getBorderColor());
- $styleWriter->setAttributes(array('space' => '24'));
+ $styleWriter->setAttributes(['space' => '24']);
$styleWriter->write();
$xmlWriter->endElement();
@@ -92,7 +93,7 @@ public function write()
// Page numbering start
$pageNum = $style->getPageNumberingStart();
- $xmlWriter->writeElementIf(!is_null($pageNum), 'w:pgNumType', 'w:start', $pageNum);
+ $xmlWriter->writeElementIf(null !== $pageNum, 'w:pgNumType', 'w:start', $pageNum);
// Line numbering
$styleWriter = new LineNumbering($xmlWriter, $style->getLineNumbering());
diff --git a/src/PhpWord/Writer/Word2007/Style/Shading.php b/src/PhpWord/Writer/Word2007/Style/Shading.php
index 0f9d6ccc08..bf7476cdb1 100644
--- a/src/PhpWord/Writer/Word2007/Style/Shading.php
+++ b/src/PhpWord/Writer/Word2007/Style/Shading.php
@@ -1,4 +1,5 @@
getStyle();
if (!$style instanceof \PhpOffice\PhpWord\Style\Shading) {
@@ -36,9 +37,9 @@ public function write()
$xmlWriter = $this->getXmlWriter();
$xmlWriter->startElement('w:shd');
- $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->writeAttributeIf(null !== $style->getPattern(), 'w:val', $style->getPattern());
+ $xmlWriter->writeAttributeIf(null !== $style->getColor(), 'w:color', $style->getColor());
+ $xmlWriter->writeAttributeIf(null !== $style->getFill(), 'w:fill', $style->getFill());
$xmlWriter->endElement();
}
}
diff --git a/src/PhpWord/Writer/Word2007/Style/Shadow.php b/src/PhpWord/Writer/Word2007/Style/Shadow.php
index 7fcb12a960..33678155b0 100644
--- a/src/PhpWord/Writer/Word2007/Style/Shadow.php
+++ b/src/PhpWord/Writer/Word2007/Style/Shadow.php
@@ -1,4 +1,5 @@
getStyle();
if (!$style instanceof \PhpOffice\PhpWord\Style\Shadow) {
diff --git a/src/PhpWord/Writer/Word2007/Style/Shape.php b/src/PhpWord/Writer/Word2007/Style/Shape.php
index 2def6842a9..06082f1e71 100644
--- a/src/PhpWord/Writer/Word2007/Style/Shape.php
+++ b/src/PhpWord/Writer/Word2007/Style/Shape.php
@@ -1,4 +1,5 @@
getStyle();
if (!$style instanceof \PhpOffice\PhpWord\Style\Shape) {
@@ -36,7 +37,7 @@ public function write()
$xmlWriter = $this->getXmlWriter();
- $childStyles = array('Frame', 'Fill', 'Outline', 'Shadow', 'Extrusion');
+ $childStyles = ['Frame', 'Fill', 'Outline', 'Shadow', 'Extrusion'];
foreach ($childStyles as $childStyle) {
$method = "get{$childStyle}";
$this->writeChildStyle($xmlWriter, $childStyle, $style->$method());
diff --git a/src/PhpWord/Writer/Word2007/Style/Spacing.php b/src/PhpWord/Writer/Word2007/Style/Spacing.php
index fdfb89ab87..6b99f5ac4b 100644
--- a/src/PhpWord/Writer/Word2007/Style/Spacing.php
+++ b/src/PhpWord/Writer/Word2007/Style/Spacing.php
@@ -1,4 +1,5 @@
getStyle();
if (!$style instanceof \PhpOffice\PhpWord\Style\Spacing) {
@@ -38,19 +39,19 @@ public function write()
$xmlWriter->startElement('w:spacing');
$before = $style->getBefore();
- $xmlWriter->writeAttributeIf(!is_null($before), 'w:before', $this->convertTwip($before));
+ $xmlWriter->writeAttributeIf(null !== $before, 'w:before', $this->convertTwip($before));
$after = $style->getAfter();
- $xmlWriter->writeAttributeIf(!is_null($after), 'w:after', $this->convertTwip($after));
+ $xmlWriter->writeAttributeIf(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(null !== $line, 'w:line', $line);
- $xmlWriter->writeAttributeIf(!is_null($line), 'w:lineRule', $style->getLineRule());
+ $xmlWriter->writeAttributeIf(null !== $line, 'w:lineRule', $style->getLineRule());
$xmlWriter->endElement();
}
diff --git a/src/PhpWord/Writer/Word2007/Style/Tab.php b/src/PhpWord/Writer/Word2007/Style/Tab.php
index b41653f6c4..4a8da4045c 100644
--- a/src/PhpWord/Writer/Word2007/Style/Tab.php
+++ b/src/PhpWord/Writer/Word2007/Style/Tab.php
@@ -1,4 +1,5 @@
getStyle();
if (!$style instanceof \PhpOffice\PhpWord\Style\Tab) {
diff --git a/src/PhpWord/Writer/Word2007/Style/Table.php b/src/PhpWord/Writer/Word2007/Style/Table.php
index 443d670582..711f3ecde7 100644
--- a/src/PhpWord/Writer/Word2007/Style/Table.php
+++ b/src/PhpWord/Writer/Word2007/Style/Table.php
@@ -1,4 +1,5 @@
getStyle();
$xmlWriter = $this->getXmlWriter();
@@ -58,11 +59,8 @@ public function write()
/**
* Write full style.
- *
- * @param \PhpOffice\Common\XMLWriter $xmlWriter
- * @param \PhpOffice\PhpWord\Style\Table $style
*/
- private function writeStyle(XMLWriter $xmlWriter, TableStyle $style)
+ private function writeStyle(XMLWriter $xmlWriter, TableStyle $style): void
{
// w:tblPr
$xmlWriter->startElement('w:tblPr');
@@ -104,12 +102,11 @@ private function writeStyle(XMLWriter $xmlWriter, TableStyle $style)
}
/**
- * Enable/Disable automatic resizing of the table
+ * Enable/Disable automatic resizing of the table.
*
- * @param \PhpOffice\Common\XMLWriter $xmlWriter
* @param string $layout autofit / fixed
*/
- private function writeLayout(XMLWriter $xmlWriter, $layout)
+ private function writeLayout(XMLWriter $xmlWriter, $layout): void
{
$xmlWriter->startElement('w:tblLayout');
$xmlWriter->writeAttribute('w:type', $layout);
@@ -118,11 +115,8 @@ private function writeLayout(XMLWriter $xmlWriter, $layout)
/**
* Write margin.
- *
- * @param \PhpOffice\Common\XMLWriter $xmlWriter
- * @param \PhpOffice\PhpWord\Style\Table $style
*/
- private function writeMargin(XMLWriter $xmlWriter, TableStyle $style)
+ private function writeMargin(XMLWriter $xmlWriter, TableStyle $style): void
{
if ($style->hasMargin()) {
$xmlWriter->startElement('w:tblCellMar');
@@ -137,11 +131,8 @@ private function writeMargin(XMLWriter $xmlWriter, TableStyle $style)
/**
* Write border.
- *
- * @param \PhpOffice\Common\XMLWriter $xmlWriter
- * @param \PhpOffice\PhpWord\Style\Table $style
*/
- private function writeBorder(XMLWriter $xmlWriter, TableStyle $style)
+ private function writeBorder(XMLWriter $xmlWriter, TableStyle $style): void
{
if ($style->hasBorder()) {
$xmlWriter->startElement('w:tblBorders');
@@ -156,31 +147,27 @@ private function writeBorder(XMLWriter $xmlWriter, TableStyle $style)
}
/**
- * Writes a table width
+ * Writes a table width.
*
- * @param \PhpOffice\Common\XMLWriter $xmlWriter
* @param string $elementName
* @param string $unit
- * @param int|float $width
+ * @param null|float|int $width
*/
- private function writeTblWidth(XMLWriter $xmlWriter, $elementName, $unit, $width = null)
+ private function writeTblWidth(XMLWriter $xmlWriter, $elementName, $unit, $width = null): void
{
if (null === $width) {
return;
}
$xmlWriter->startElement($elementName);
- $xmlWriter->writeAttributeIf(null !== $width, 'w:w', $width);
+ $xmlWriter->writeAttribute('w:w', $width);
$xmlWriter->writeAttribute('w:type', $unit);
$xmlWriter->endElement();
}
/**
* Write row style.
- *
- * @param \PhpOffice\Common\XMLWriter $xmlWriter
- * @param \PhpOffice\PhpWord\Style\Table $style
*/
- private function writeFirstRow(XMLWriter $xmlWriter, TableStyle $style)
+ private function writeFirstRow(XMLWriter $xmlWriter, TableStyle $style): void
{
$xmlWriter->startElement('w:tblStylePr');
$xmlWriter->writeAttribute('w:type', 'firstRow');
@@ -195,11 +182,8 @@ private function writeFirstRow(XMLWriter $xmlWriter, TableStyle $style)
/**
* Write shading.
- *
- * @param \PhpOffice\Common\XMLWriter $xmlWriter
- * @param \PhpOffice\PhpWord\Style\Table $style
*/
- private function writeShading(XMLWriter $xmlWriter, TableStyle $style)
+ private function writeShading(XMLWriter $xmlWriter, TableStyle $style): void
{
if (null !== $style->getShading()) {
$xmlWriter->startElement('w:tcPr');
@@ -216,16 +200,12 @@ private function writeShading(XMLWriter $xmlWriter, TableStyle $style)
*
* @param int $value
*/
- public function setWidth($value = null)
+ public function setWidth($value = null): void
{
$this->width = $value;
}
- /**
- * @param XMLWriter $xmlWriter
- * @param TableStyle $style
- */
- private function writeIndent(XMLWriter $xmlWriter, TableStyle $style)
+ private function writeIndent(XMLWriter $xmlWriter, TableStyle $style): void
{
$indent = $style->getIndent();
diff --git a/src/PhpWord/Writer/Word2007/Style/TablePosition.php b/src/PhpWord/Writer/Word2007/Style/TablePosition.php
index fa57b93c2f..71668032e5 100644
--- a/src/PhpWord/Writer/Word2007/Style/TablePosition.php
+++ b/src/PhpWord/Writer/Word2007/Style/TablePosition.php
@@ -1,4 +1,5 @@
getStyle();
if (!$style instanceof \PhpOffice\PhpWord\Style\TablePosition) {
return;
}
- $values = array();
- $properties = array(
- 'leftFromText',
- 'rightFromText',
- 'topFromText',
- 'bottomFromText',
- 'vertAnchor',
- 'horzAnchor',
- 'tblpXSpec',
- 'tblpX',
- 'tblpYSpec',
- 'tblpY',
- );
+ $values = [];
+ $properties = [
+ 'leftFromText',
+ 'rightFromText',
+ 'topFromText',
+ 'bottomFromText',
+ 'vertAnchor',
+ 'horzAnchor',
+ 'tblpXSpec',
+ 'tblpX',
+ 'tblpYSpec',
+ 'tblpY',
+ ];
foreach ($properties as $property) {
$method = 'get' . $property;
if (method_exists($style, $method)) {
diff --git a/src/PhpWord/Writer/Word2007/Style/TextBox.php b/src/PhpWord/Writer/Word2007/Style/TextBox.php
index 627d0c86e5..2f8b5e9b3d 100644
--- a/src/PhpWord/Writer/Word2007/Style/TextBox.php
+++ b/src/PhpWord/Writer/Word2007/Style/TextBox.php
@@ -1,17 +1,16 @@
getStyle();
if (!$style instanceof TextBoxStyle || !$style->hasInnerMargins()) {
@@ -45,7 +44,7 @@ public function writeInnerMargin()
/**
* Writer border.
*/
- public function writeBorder()
+ public function writeBorder(): void
{
$style = $this->getStyle();
if (!$style instanceof TextBoxStyle) {
diff --git a/src/PhpWord/Writer/WriterInterface.php b/src/PhpWord/Writer/WriterInterface.php
index 499cde3bb1..86743e7bd2 100644
--- a/src/PhpWord/Writer/WriterInterface.php
+++ b/src/PhpWord/Writer/WriterInterface.php
@@ -1,4 +1,5 @@
getMockForAbstractClass('\PhpOffice\PhpWord\Element\AbstractElement');
- $ival = rand(0, 100);
- $stub->setElementIndex($ival);
- $this->assertEquals($ival, $stub->getElementIndex());
- }
-
- /**
- * Test set/get element unique Id
- */
- public function testElementId()
- {
- $stub = $this->getMockForAbstractClass('\PhpOffice\PhpWord\Element\AbstractElement');
- $stub->setElementId();
- $this->assertEquals(6, strlen($stub->getElementId()));
- }
-}
diff --git a/tests/PhpWord/Element/CellTest.php b/tests/PhpWord/Element/CellTest.php
deleted file mode 100644
index 7e63967a96..0000000000
--- a/tests/PhpWord/Element/CellTest.php
+++ /dev/null
@@ -1,273 +0,0 @@
-assertInstanceOf('PhpOffice\\PhpWord\\Element\\Cell', $oCell);
- $this->assertNull($oCell->getWidth());
- }
-
- /**
- * New instance with array
- */
- public function testConstructWithStyleArray()
- {
- $oCell = new Cell(null, array('valign' => 'center'));
-
- $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Cell', $oCell->getStyle());
- $this->assertNull($oCell->getWidth());
- }
-
- /**
- * Add text
- */
- public function testAddText()
- {
- $oCell = new Cell();
- $element = $oCell->addText('text');
-
- $this->assertCount(1, $oCell->getElements());
- $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Text', $element);
- }
-
- /**
- * Add non-UTF8
- */
- public function testAddTextNotUTF8()
- {
- $oCell = new Cell();
- $element = $oCell->addText(utf8_decode('ééé'));
-
- $this->assertCount(1, $oCell->getElements());
- $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Text', $element);
- $this->assertEquals('ééé', $element->getText());
- }
-
- /**
- * Add link
- */
- public function testAddLink()
- {
- $oCell = new Cell();
- $element = $oCell->addLink(utf8_decode('ééé'), utf8_decode('ééé'));
-
- $this->assertCount(1, $oCell->getElements());
- $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Link', $element);
- }
-
- /**
- * Add text break
- */
- public function testAddTextBreak()
- {
- $oCell = new Cell();
- $oCell->addTextBreak();
-
- $this->assertCount(1, $oCell->getElements());
- }
-
- /**
- * Add list item
- */
- public function testAddListItem()
- {
- $oCell = new Cell();
- $element = $oCell->addListItem('text');
-
- $this->assertCount(1, $oCell->getElements());
- $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\ListItem', $element);
- $this->assertEquals('text', $element->getTextObject()->getText());
- }
-
- /**
- * Add list item non-UTF8
- */
- public function testAddListItemNotUTF8()
- {
- $oCell = new Cell();
- $element = $oCell->addListItem(utf8_decode('ééé'));
-
- $this->assertCount(1, $oCell->getElements());
- $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\ListItem', $element);
- $this->assertEquals('ééé', $element->getTextObject()->getText());
- }
-
- /**
- * Add image section
- */
- public function testAddImageSection()
- {
- $src = __DIR__ . '/../_files/images/earth.jpg';
- $oCell = new Cell();
- $element = $oCell->addImage($src);
-
- $this->assertCount(1, $oCell->getElements());
- $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Image', $element);
- }
-
- /**
- * Add image header
- */
- public function testAddImageHeader()
- {
- $src = __DIR__ . '/../_files/images/earth.jpg';
- $oCell = new Cell('header', 1);
- $element = $oCell->addImage($src);
-
- $this->assertCount(1, $oCell->getElements());
- $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Image', $element);
- }
-
- /**
- * Add image footer
- */
- public function testAddImageFooter()
- {
- $src = __DIR__ . '/../_files/images/earth.jpg';
- $oCell = new Cell('footer', 1);
- $element = $oCell->addImage($src);
-
- $this->assertCount(1, $oCell->getElements());
- $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Image', $element);
- }
-
- /**
- * Add image section by URL
- */
- public function testAddImageSectionByUrl()
- {
- $oCell = new Cell();
- $element = $oCell->addImage(self::getRemoteGifImageUrl());
-
- $this->assertCount(1, $oCell->getElements());
- $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Image', $element);
- }
-
- /**
- * Add object
- */
- public function testAddObjectXLS()
- {
- $src = __DIR__ . '/../_files/documents/sheet.xls';
- $oCell = new Cell();
- $element = $oCell->addObject($src);
-
- $this->assertCount(1, $oCell->getElements());
- $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\OLEObject', $element);
- }
-
- /**
- * Test add object exception
- *
- * @expectedException \PhpOffice\PhpWord\Exception\InvalidObjectException
- */
- public function testAddObjectException()
- {
- $src = __DIR__ . '/../_files/xsl/passthrough.xsl';
- $oCell = new Cell();
- $oCell->addObject($src);
- }
-
- /**
- * Add preserve text
- */
- public function testAddPreserveText()
- {
- $oCell = new Cell();
- $oCell->setDocPart('Header', 1);
- $element = $oCell->addPreserveText('text');
-
- $this->assertCount(1, $oCell->getElements());
- $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\PreserveText', $element);
- }
-
- /**
- * Add preserve text non-UTF8
- */
- public function testAddPreserveTextNotUTF8()
- {
- $oCell = new Cell();
- $oCell->setDocPart('Header', 1);
- $element = $oCell->addPreserveText(utf8_decode('ééé'));
-
- $this->assertCount(1, $oCell->getElements());
- $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\PreserveText', $element);
- $this->assertEquals(array('ééé'), $element->getText());
- }
-
- /**
- * Add preserve text exception
- *
- * @expectedException \BadMethodCallException
- */
- public function testAddPreserveTextException()
- {
- $oCell = new Cell();
- $oCell->setDocPart('Section', 1);
- $oCell->addPreserveText('text');
- }
-
- /**
- * Add text run
- */
- public function testCreateTextRun()
- {
- $oCell = new Cell();
- $element = $oCell->addTextRun();
-
- $this->assertCount(1, $oCell->getElements());
- $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\TextRun', $element);
- }
-
- /**
- * Add check box
- */
- public function testAddCheckBox()
- {
- $oCell = new Cell();
- $element = $oCell->addCheckBox(utf8_decode('ééé'), utf8_decode('ééé'));
-
- $this->assertCount(1, $oCell->getElements());
- $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\CheckBox', $element);
- }
-
- /**
- * Get elements
- */
- public function testGetElements()
- {
- $oCell = new Cell();
-
- $this->assertInternalType('array', $oCell->getElements());
- }
-}
diff --git a/tests/PhpWord/Element/CheckBoxTest.php b/tests/PhpWord/Element/CheckBoxTest.php
deleted file mode 100644
index f732407b06..0000000000
--- a/tests/PhpWord/Element/CheckBoxTest.php
+++ /dev/null
@@ -1,87 +0,0 @@
-assertInstanceOf('PhpOffice\\PhpWord\\Element\\CheckBox', $oCheckBox);
- $this->assertNull($oCheckBox->getText());
- $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Font', $oCheckBox->getFontStyle());
- $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Paragraph', $oCheckBox->getParagraphStyle());
- }
-
- /**
- * Get name and text
- */
- public function testCheckBox()
- {
- $oCheckBox = new CheckBox('chkBox', 'CheckBox');
-
- $this->assertEquals('chkBox', $oCheckBox->getName());
- $this->assertEquals('CheckBox', $oCheckBox->getText());
- }
-
- /**
- * Get font style
- */
- public function testFont()
- {
- $oCheckBox = new CheckBox('chkBox', 'CheckBox', 'fontStyle');
- $this->assertEquals('fontStyle', $oCheckBox->getFontStyle());
-
- $oCheckBox->setFontStyle(array('bold' => true, 'italic' => true, 'size' => 16));
- $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Font', $oCheckBox->getFontStyle());
- }
-
- /**
- * Font style as object
- */
- public function testFontObject()
- {
- $font = new Font();
- $oCheckBox = new CheckBox('chkBox', 'CheckBox', $font);
- $this->assertEquals($font, $oCheckBox->getFontStyle());
- }
-
- /**
- * Get paragraph style
- */
- public function testParagraph()
- {
- $oCheckBox = new CheckBox('chkBox', 'CheckBox', 'fontStyle', 'paragraphStyle');
- $this->assertEquals('paragraphStyle', $oCheckBox->getParagraphStyle());
-
- $oCheckBox->setParagraphStyle(array('alignment' => Jc::CENTER, 'spaceAfter' => 100));
- $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Paragraph', $oCheckBox->getParagraphStyle());
- }
-}
diff --git a/tests/PhpWord/Element/CommentTest.php b/tests/PhpWord/Element/CommentTest.php
deleted file mode 100644
index b9c3dfce5a..0000000000
--- a/tests/PhpWord/Element/CommentTest.php
+++ /dev/null
@@ -1,103 +0,0 @@
-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());
- }
-
- /**
- * @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
deleted file mode 100644
index 1c1c0ca1ef..0000000000
--- a/tests/PhpWord/Element/FieldTest.php
+++ /dev/null
@@ -1,161 +0,0 @@
-assertInstanceOf('PhpOffice\\PhpWord\\Element\\Field', $oField);
- }
-
- /**
- * New instance with type
- */
- public function testConstructWithType()
- {
- $oField = new Field('DATE');
-
- $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Field', $oField);
- $this->assertEquals('DATE', $oField->getType());
- }
-
- /**
- * New instance with type and properties
- */
- public function testConstructWithTypeProperties()
- {
- $oField = new Field('DATE', array('dateformat' => 'd-M-yyyy'));
-
- $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Field', $oField);
- $this->assertEquals('DATE', $oField->getType());
- $this->assertEquals(array('dateformat' => 'd-M-yyyy'), $oField->getProperties());
- }
-
- /**
- * New instance with type and properties and options
- */
- public function testConstructWithTypePropertiesOptions()
- {
- $oField = new Field('DATE', array('dateformat' => 'd-M-yyyy'), array('SakaEraCalendar', 'PreserveFormat'));
-
- $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Field', $oField);
- $this->assertEquals('DATE', $oField->getType());
- $this->assertEquals(array('dateformat' => 'd-M-yyyy'), $oField->getProperties());
- $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
- *
- * @expectedException \InvalidArgumentException
- * @expectedExceptionMessage Invalid type
- */
- public function testSetTypeException()
- {
- $object = new Field();
- $object->setType('foo');
- }
-
- /**
- * Test setProperties exception
- *
- * @expectedException \InvalidArgumentException
- * @expectedExceptionMessage Invalid property
- */
- public function testSetPropertiesException()
- {
- $object = new Field('PAGE');
- $object->setProperties(array('foo' => 'bar'));
- }
-
- /**
- * Test setOptions exception
- *
- * @expectedException \InvalidArgumentException
- * @expectedExceptionMessage Invalid option
- */
- public function testSetOptionsException()
- {
- $object = new Field('PAGE');
- $object->setOptions(array('foo' => 'bar'));
- }
-
- /**
- * Test setText exception
- *
- * @expectedException \InvalidArgumentException
- * @expectedExceptionMessage Invalid text
- */
- public function testSetTextException()
- {
- $object = new Field('XE');
- $object->setText(array());
- }
-}
diff --git a/tests/PhpWord/Element/FooterTest.php b/tests/PhpWord/Element/FooterTest.php
deleted file mode 100644
index b1ef467750..0000000000
--- a/tests/PhpWord/Element/FooterTest.php
+++ /dev/null
@@ -1,175 +0,0 @@
-assertInstanceOf('PhpOffice\\PhpWord\\Element\\Footer', $oFooter);
- $this->assertEquals($iVal, $oFooter->getSectionId());
- }
-
- /**
- * Add text
- */
- public function testAddText()
- {
- $oFooter = new Footer(1);
- $element = $oFooter->addText('text');
-
- $this->assertCount(1, $oFooter->getElements());
- $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Text', $element);
- }
-
- /**
- * Add text non-UTF8
- */
- public function testAddTextNotUTF8()
- {
- $oFooter = new Footer(1);
- $element = $oFooter->addText(utf8_decode('ééé'));
-
- $this->assertCount(1, $oFooter->getElements());
- $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Text', $element);
- $this->assertEquals('ééé', $element->getText());
- }
-
- /**
- * Add text break
- */
- public function testAddTextBreak()
- {
- $oFooter = new Footer(1);
- $iVal = rand(1, 1000);
- $oFooter->addTextBreak($iVal);
-
- $this->assertCount($iVal, $oFooter->getElements());
- }
-
- /**
- * Add text run
- */
- public function testCreateTextRun()
- {
- $oFooter = new Footer(1);
- $element = $oFooter->addTextRun();
-
- $this->assertCount(1, $oFooter->getElements());
- $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\TextRun', $element);
- }
-
- /**
- * Add table
- */
- public function testAddTable()
- {
- $oFooter = new Footer(1);
- $element = $oFooter->addTable();
-
- $this->assertCount(1, $oFooter->getElements());
- $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Table', $element);
- }
-
- /**
- * Add image
- */
- public function testAddImage()
- {
- $src = __DIR__ . '/../_files/images/earth.jpg';
- $oFooter = new Footer(1);
- $element = $oFooter->addImage($src);
-
- $this->assertCount(1, $oFooter->getElements());
- $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Image', $element);
- }
-
- /**
- * Add image by URL
- */
- public function testAddImageByUrl()
- {
- $oFooter = new Footer(1);
- $element = $oFooter->addImage(self::getRemoteGifImageUrl());
-
- $this->assertCount(1, $oFooter->getElements());
- $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Image', $element);
- }
-
- /**
- * Add preserve text
- */
- public function testAddPreserveText()
- {
- $oFooter = new Footer(1);
- $element = $oFooter->addPreserveText('text');
-
- $this->assertCount(1, $oFooter->getElements());
- $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\PreserveText', $element);
- }
-
- /**
- * Add preserve text non-UTF8
- */
- public function testAddPreserveTextNotUTF8()
- {
- $oFooter = new Footer(1);
- $element = $oFooter->addPreserveText(utf8_decode('ééé'));
-
- $this->assertCount(1, $oFooter->getElements());
- $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\PreserveText', $element);
- $this->assertEquals(array('ééé'), $element->getText());
- }
-
- /**
- * Get elements
- */
- public function testGetElements()
- {
- $oFooter = new Footer(1);
-
- $this->assertInternalType('array', $oFooter->getElements());
- }
-
- /**
- * Set/get relation Id
- */
- public function testRelationID()
- {
- $oFooter = new Footer(0);
-
- $iVal = rand(1, 1000);
- $oFooter->setRelationId($iVal);
-
- $this->assertEquals($iVal, $oFooter->getRelationId());
- $this->assertEquals(Footer::AUTO, $oFooter->getType());
- }
-}
diff --git a/tests/PhpWord/Element/FootnoteTest.php b/tests/PhpWord/Element/FootnoteTest.php
deleted file mode 100644
index 4ea330f5ac..0000000000
--- a/tests/PhpWord/Element/FootnoteTest.php
+++ /dev/null
@@ -1,117 +0,0 @@
-assertInstanceOf('PhpOffice\\PhpWord\\Element\\Footnote', $oFootnote);
- $this->assertCount(0, $oFootnote->getElements());
- $this->assertNull($oFootnote->getParagraphStyle());
- }
-
- /**
- * New instance with string parameter
- */
- public function testConstructString()
- {
- $oFootnote = new Footnote('pStyle');
-
- $this->assertEquals('pStyle', $oFootnote->getParagraphStyle());
- }
-
- /**
- * New instance with array parameter
- */
- public function testConstructArray()
- {
- $oFootnote = new Footnote(array('spacing' => 100));
-
- $this->assertInstanceOf(
- 'PhpOffice\\PhpWord\\Style\\Paragraph',
- $oFootnote->getParagraphStyle()
- );
- }
-
- /**
- * Add text element
- */
- public function testAddText()
- {
- $oFootnote = new Footnote();
- $element = $oFootnote->addText('text');
-
- $this->assertCount(1, $oFootnote->getElements());
- $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Text', $element);
- }
-
- /**
- * Add text break element
- */
- public function testAddTextBreak()
- {
- $oFootnote = new Footnote();
- $oFootnote->addTextBreak(2);
-
- $this->assertCount(2, $oFootnote->getElements());
- }
-
- /**
- * Add link element
- */
- public function testAddLink()
- {
- $oFootnote = new Footnote();
- $element = $oFootnote->addLink('https://github.com/PHPOffice/PHPWord');
-
- $this->assertCount(1, $oFootnote->getElements());
- $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Link', $element);
- }
-
- /**
- * Set/get reference Id
- */
- public function testReferenceId()
- {
- $oFootnote = new Footnote();
-
- $iVal = rand(1, 1000);
- $oFootnote->setRelationId($iVal);
- $this->assertEquals($iVal, $oFootnote->getRelationId());
- }
-
- /**
- * Get elements
- */
- public function testGetElements()
- {
- $oFootnote = new Footnote();
- $this->assertInternalType('array', $oFootnote->getElements());
- }
-}
diff --git a/tests/PhpWord/Element/HeaderTest.php b/tests/PhpWord/Element/HeaderTest.php
deleted file mode 100644
index 4bbf7b74f3..0000000000
--- a/tests/PhpWord/Element/HeaderTest.php
+++ /dev/null
@@ -1,252 +0,0 @@
-assertInstanceOf('PhpOffice\\PhpWord\\Element\\Header', $oHeader);
- $this->assertEquals($iVal, $oHeader->getSectionId());
- $this->assertEquals(Header::AUTO, $oHeader->getType());
- }
-
- /**
- * Add text
- */
- public function testAddText()
- {
- $oHeader = new Header(1);
- $element = $oHeader->addText('text');
-
- $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Text', $element);
- $this->assertCount(1, $oHeader->getElements());
- $this->assertEquals('text', $element->getText());
- }
-
- /**
- * Add text non-UTF8
- */
- public function testAddTextNotUTF8()
- {
- $oHeader = new Header(1);
- $element = $oHeader->addText(utf8_decode('ééé'));
-
- $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Text', $element);
- $this->assertCount(1, $oHeader->getElements());
- $this->assertEquals('ééé', $element->getText());
- }
-
- /**
- * Add text break
- */
- public function testAddTextBreak()
- {
- $oHeader = new Header(1);
- $oHeader->addTextBreak();
- $this->assertCount(1, $oHeader->getElements());
- }
-
- /**
- * Add text break with params
- */
- public function testAddTextBreakWithParams()
- {
- $oHeader = new Header(1);
- $iVal = rand(1, 1000);
- $oHeader->addTextBreak($iVal);
- $this->assertCount($iVal, $oHeader->getElements());
- }
-
- /**
- * Add text run
- */
- public function testCreateTextRun()
- {
- $oHeader = new Header(1);
- $element = $oHeader->addTextRun();
- $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\TextRun', $element);
- $this->assertCount(1, $oHeader->getElements());
- }
-
- /**
- * Add table
- */
- public function testAddTable()
- {
- $oHeader = new Header(1);
- $element = $oHeader->addTable();
- $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Table', $element);
- $this->assertCount(1, $oHeader->getElements());
- }
-
- /**
- * Add image
- */
- public function testAddImage()
- {
- $src = __DIR__ . '/../_files/images/earth.jpg';
- $oHeader = new Header(1);
- $element = $oHeader->addImage($src);
-
- $this->assertCount(1, $oHeader->getElements());
- $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Image', $element);
- }
-
- /**
- * Add image by URL
- */
- public function testAddImageByUrl()
- {
- $oHeader = new Header(1);
- $element = $oHeader->addImage(self::getRemoteGifImageUrl());
-
- $this->assertCount(1, $oHeader->getElements());
- $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Image', $element);
- }
-
- /**
- * Add preserve text
- */
- public function testAddPreserveText()
- {
- $oHeader = new Header(1);
- $element = $oHeader->addPreserveText('text');
-
- $this->assertCount(1, $oHeader->getElements());
- $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\PreserveText', $element);
- }
-
- /**
- * Add preserve text non-UTF8
- */
- public function testAddPreserveTextNotUTF8()
- {
- $oHeader = new Header(1);
- $element = $oHeader->addPreserveText(utf8_decode('ééé'));
-
- $this->assertCount(1, $oHeader->getElements());
- $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\PreserveText', $element);
- $this->assertEquals(array('ééé'), $element->getText());
- }
-
- /**
- * Add watermark
- */
- public function testAddWatermark()
- {
- $src = __DIR__ . '/../_files/images/earth.jpg';
- $oHeader = new Header(1);
- $element = $oHeader->addWatermark($src);
-
- $this->assertCount(1, $oHeader->getElements());
- $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Image', $element);
- }
-
- /**
- * Get elements
- */
- public function testGetElements()
- {
- $oHeader = new Header(1);
-
- $this->assertInternalType('array', $oHeader->getElements());
- }
-
- /**
- * Set/get relation Id
- */
- public function testRelationId()
- {
- $oHeader = new Header(1);
-
- $iVal = rand(1, 1000);
- $oHeader->setRelationId($iVal);
- $this->assertEquals($iVal, $oHeader->getRelationId());
- }
-
- /**
- * Reset type
- */
- public function testResetType()
- {
- $oHeader = new Header(1);
- $oHeader->firstPage();
- $oHeader->resetType();
-
- $this->assertEquals(Header::AUTO, $oHeader->getType());
- }
-
- /**
- * First page
- */
- public function testFirstPage()
- {
- $oHeader = new Header(1);
- $oHeader->firstPage();
-
- $this->assertEquals(Header::FIRST, $oHeader->getType());
- }
-
- /**
- * Even page
- */
- public function testEvenPage()
- {
- $oHeader = new Header(1);
- $oHeader->evenPage();
-
- $this->assertEquals(Header::EVEN, $oHeader->getType());
- }
-
- /**
- * Add footnote exception
- *
- * @expectedException \BadMethodCallException
- */
- public function testAddFootnoteException()
- {
- $header = new Header(1);
- $header->addFootnote();
- }
-
- /**
- * Set/get type
- */
- public function testSetGetType()
- {
- $object = new Header(1);
- $this->assertEquals(Header::AUTO, $object->getType());
-
- $object->setType('ODD');
- $this->assertEquals(Header::AUTO, $object->getType());
- }
-}
diff --git a/tests/PhpWord/Element/ImageTest.php b/tests/PhpWord/Element/ImageTest.php
deleted file mode 100644
index f56d079487..0000000000
--- a/tests/PhpWord/Element/ImageTest.php
+++ /dev/null
@@ -1,245 +0,0 @@
-assertInstanceOf('PhpOffice\\PhpWord\\Element\\Image', $oImage);
- $this->assertEquals($src, $oImage->getSource());
- $this->assertEquals(md5($src), $oImage->getMediaId());
- $this->assertFalse($oImage->isWatermark());
- $this->assertEquals(Image::SOURCE_LOCAL, $oImage->getSourceType());
- $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Image', $oImage->getStyle());
- }
-
- /**
- * New instance with style
- */
- public function testConstructWithStyle()
- {
- $src = __DIR__ . '/../_files/images/firefox.png';
- $oImage = new Image(
- $src,
- array(
- 'width' => 210,
- 'height' => 210,
- 'alignment' => Jc::CENTER,
- 'wrappingStyle' => \PhpOffice\PhpWord\Style\Image::WRAPPING_STYLE_BEHIND,
- )
- );
-
- $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Image', $oImage->getStyle());
- }
-
- /**
- * Valid image types
- */
- public function testImages()
- {
- $images = array(
- array('mars.jpg', 'image/jpeg', 'jpg', 'imagecreatefromjpeg', 'imagejpeg'),
- array('mario.gif', 'image/gif', 'gif', 'imagecreatefromgif', 'imagegif'),
- array('firefox.png', 'image/png', 'png', 'imagecreatefrompng', 'imagepng'),
- array('duke_nukem.bmp', 'image/bmp', 'bmp', null, null),
- array('angela_merkel.tif', 'image/tiff', 'tif', null, null),
- );
-
- foreach ($images as $imageData) {
- list($source, $type, $extension, $createFunction, $imageFunction) = $imageData;
- $source = __DIR__ . "/../_files/images/{$source}";
- $image = new Image($source);
- $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Image', $image);
- $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());
- $this->assertNotNull($image->getImageStringData());
- }
- }
-
- /**
- * Get style
- */
- public function testStyle()
- {
- $oImage = new Image(
- __DIR__ . '/../_files/images/earth.jpg',
- array('height' => 210, 'alignment' => Jc::CENTER)
- );
-
- $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Image', $oImage->getStyle());
- }
-
- /**
- * Test invalid local image
- *
- * @expectedException \PhpOffice\PhpWord\Exception\InvalidImageException
- */
- public function testInvalidImageLocal()
- {
- new Image(__DIR__ . '/../_files/images/thisisnotarealimage');
- }
-
- /**
- * Test invalid PHP Image
- *
- * @expectedException \PhpOffice\PhpWord\Exception\InvalidImageException
- */
- public function testInvalidImagePhp()
- {
- $object = new Image('test.php');
- $object->getSource();
- }
-
- /**
- * Test unsupported image
- *
- * @expectedException \PhpOffice\PhpWord\Exception\UnsupportedImageTypeException
- */
- public function testUnsupportedImage()
- {
- //disable ssl verification, never do this in real application, you should pass the certificiate instead!!!
- $arrContextOptions = array(
- 'ssl' => array(
- 'verify_peer' => false,
- 'verify_peer_name' => false,
- ),
- );
- stream_context_set_default($arrContextOptions);
- $object = new Image(self::getRemoteBmpImageUrl());
- $object->getSource();
- }
-
- /**
- * Get relation Id
- */
- public function testRelationID()
- {
- $oImage = new Image(__DIR__ . '/../_files/images/earth.jpg', array('width' => 100));
- $iVal = rand(1, 1000);
- $oImage->setRelationId($iVal);
- $this->assertEquals($iVal, $oImage->getRelationId());
- }
-
- /**
- * Test archived image
- */
- public function testArchivedImage()
- {
- $archiveFile = __DIR__ . '/../_files/documents/reader.docx';
- $imageFile = 'word/media/image1.jpeg';
- $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('imagecreatefromstring', $image->getImageCreateFunction());
- $this->assertEquals('imagejpeg', $image->getImageFunction());
- $this->assertTrue($image->isMemImage());
-
- $this->assertNotNull($image->getImageStringData());
- $this->assertNotNull($image->getImageStringData(true));
- }
-
- /**
- * Test construct from GD
- */
- public function testConstructFromGd()
- {
- $source = self::getRemoteImageUrl();
-
- $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
- *
- * @expectedException \PhpOffice\PhpWord\Exception\InvalidImageException
- */
- public function testInvalidImageString()
- {
- $object = new Image('this_is-a_non_valid_image');
- $object->getSource();
- }
-}
diff --git a/tests/PhpWord/Element/LineTest.php b/tests/PhpWord/Element/LineTest.php
deleted file mode 100644
index 20eee74f38..0000000000
--- a/tests/PhpWord/Element/LineTest.php
+++ /dev/null
@@ -1,74 +0,0 @@
-assertInstanceOf('PhpOffice\\PhpWord\\Element\\Line', $oLine);
- $this->assertNull($oLine->getStyle());
- }
-
- /**
- * Get style name
- */
- public function testStyleText()
- {
- $oLine = new Line('lineStyle');
-
- $this->assertEquals('lineStyle', $oLine->getStyle());
- }
-
- /**
- * Get style array
- */
- public function testStyleArray()
- {
- $oLine = new Line(
- array(
- '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,
- )
- );
-
- $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Line', $oLine->getStyle());
- }
-}
diff --git a/tests/PhpWord/Element/LinkTest.php b/tests/PhpWord/Element/LinkTest.php
deleted file mode 100644
index e1be7521a6..0000000000
--- a/tests/PhpWord/Element/LinkTest.php
+++ /dev/null
@@ -1,85 +0,0 @@
-assertInstanceOf('PhpOffice\\PhpWord\\Element\\Link', $oLink);
- $this->assertEquals('https://github.com/PHPOffice/PHPWord', $oLink->getSource());
- $this->assertEquals($oLink->getSource(), $oLink->getText());
- $this->assertNull($oLink->getFontStyle());
- $this->assertNull($oLink->getParagraphStyle());
- }
-
- /**
- * Create new instance with array
- */
- public function testConstructWithParamsArray()
- {
- $oLink = new Link(
- 'https://github.com/PHPOffice/PHPWord',
- '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('PHPWord on GitHub', $oLink->getText());
- $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Font', $oLink->getFontStyle());
- $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Paragraph', $oLink->getParagraphStyle());
- }
-
- /**
- * Create new instance with style name string
- */
- public function testConstructWithParamsString()
- {
- $oLink = new Link('https://github.com/PHPOffice/PHPWord', null, 'fontStyle', 'paragraphStyle');
-
- $this->assertEquals('fontStyle', $oLink->getFontStyle());
- $this->assertEquals('paragraphStyle', $oLink->getParagraphStyle());
- }
-
- /**
- * Set/get relation Id
- */
- public function testRelationId()
- {
- $oLink = new Link('https://github.com/PHPOffice/PHPWord');
-
- $iVal = rand(1, 1000);
- $oLink->setRelationId($iVal);
- $this->assertEquals($iVal, $oLink->getRelationId());
- }
-}
diff --git a/tests/PhpWord/Element/ListItemRunTest.php b/tests/PhpWord/Element/ListItemRunTest.php
deleted file mode 100644
index 95eb17eb29..0000000000
--- a/tests/PhpWord/Element/ListItemRunTest.php
+++ /dev/null
@@ -1,173 +0,0 @@
-assertInstanceOf('PhpOffice\\PhpWord\\Element\\ListItemRun', $oListItemRun);
- $this->assertCount(0, $oListItemRun->getElements());
- $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Paragraph', $oListItemRun->getParagraphStyle());
- }
-
- /**
- * New instance with string
- */
- public function testConstructString()
- {
- $oListItemRun = new ListItemRun(0, null, 'pStyle');
-
- $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\ListItemRun', $oListItemRun);
- $this->assertCount(0, $oListItemRun->getElements());
- $this->assertEquals('pStyle', $oListItemRun->getParagraphStyle());
- }
-
- /**
- * New instance with string
- */
- public function testConstructListString()
- {
- $oListItemRun = new ListItemRun(0, 'numberingStyle');
-
- $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\ListItemRun', $oListItemRun);
- $this->assertCount(0, $oListItemRun->getElements());
- }
-
- /**
- * New instance with array
- */
- public function testConstructArray()
- {
- $oListItemRun = new ListItemRun(0, null, array('spacing' => 100));
-
- $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\ListItemRun', $oListItemRun);
- $this->assertCount(0, $oListItemRun->getElements());
- $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Paragraph', $oListItemRun->getParagraphStyle());
- }
-
- /**
- * Get style
- */
- 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(\PhpOffice\PhpWord\Style\ListItem::TYPE_NUMBER, $oListItemRun->getStyle()->getListType());
- }
-
- /**
- * getDepth
- */
- public function testDepth()
- {
- $iVal = rand(1, 1000);
- $oListItemRun = new ListItemRun($iVal);
-
- $this->assertEquals($iVal, $oListItemRun->getDepth());
- }
-
- /**
- * Add text
- */
- public function testAddText()
- {
- $oListItemRun = new ListItemRun();
- $element = $oListItemRun->addText('text');
-
- $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Text', $element);
- $this->assertCount(1, $oListItemRun->getElements());
- $this->assertEquals('text', $element->getText());
- }
-
- /**
- * Add text non-UTF8
- */
- public function testAddTextNotUTF8()
- {
- $oListItemRun = new ListItemRun();
- $element = $oListItemRun->addText(utf8_decode('ééé'));
-
- $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Text', $element);
- $this->assertCount(1, $oListItemRun->getElements());
- $this->assertEquals('ééé', $element->getText());
- }
-
- /**
- * Add link
- */
- public function testAddLink()
- {
- $oListItemRun = new ListItemRun();
- $element = $oListItemRun->addLink('https://github.com/PHPOffice/PHPWord');
-
- $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Link', $element);
- $this->assertCount(1, $oListItemRun->getElements());
- $this->assertEquals('https://github.com/PHPOffice/PHPWord', $element->getSource());
- }
-
- /**
- * Add link with name
- */
- public function testAddLinkWithName()
- {
- $oListItemRun = new ListItemRun();
- $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('PHPWord on GitHub', $element->getText());
- }
-
- /**
- * Add text break
- */
- public function testAddTextBreak()
- {
- $oListItemRun = new ListItemRun();
- $oListItemRun->addTextBreak(2);
-
- $this->assertCount(2, $oListItemRun->getElements());
- }
-
- /**
- * Add image
- */
- public function testAddImage()
- {
- $src = __DIR__ . '/../_files/images/earth.jpg';
-
- $oListItemRun = new ListItemRun();
- $element = $oListItemRun->addImage($src);
-
- $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Image', $element);
- $this->assertCount(1, $oListItemRun->getElements());
- }
-}
diff --git a/tests/PhpWord/Element/ObjectTest.php b/tests/PhpWord/Element/ObjectTest.php
deleted file mode 100644
index 9fbe1bb554..0000000000
--- a/tests/PhpWord/Element/ObjectTest.php
+++ /dev/null
@@ -1,104 +0,0 @@
-assertInstanceOf('PhpOffice\\PhpWord\\Element\\OLEObject', $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 OLEObject($src);
-
- $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\OLEObject', $oObject);
- $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Image', $oObject->getStyle());
- $this->assertEquals($src, $oObject->getSource());
- }
-
- /**
- * Create new instance with non-supported files
- *
- * @expectedException \PhpOffice\PhpWord\Exception\InvalidObjectException
- */
- public function testConstructWithNotSupportedFiles()
- {
- $src = __DIR__ . '/../_files/xsl/passthrough.xsl';
- $oObject = new OLEObject($src);
- $oObject->getSource();
- }
-
- /**
- * Create with style
- */
- public function testConstructWithSupportedFilesAndStyle()
- {
- $src = __DIR__ . '/../_files/documents/sheet.xls';
- $oObject = new OLEObject($src, array('width' => '230px'));
-
- $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\OLEObject', $oObject);
- $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Image', $oObject->getStyle());
- $this->assertEquals($src, $oObject->getSource());
- }
-
- /**
- * Set/get relation Id
- */
- public function testRelationId()
- {
- $src = __DIR__ . '/../_files/documents/sheet.xls';
- $oObject = new OLEObject($src);
-
- $iVal = rand(1, 1000);
- $oObject->setRelationId($iVal);
- $this->assertEquals($iVal, $oObject->getRelationId());
- }
-
- /**
- * Set/get image relation Id
- */
- public function testImageRelationId()
- {
- $src = __DIR__ . '/../_files/documents/sheet.xls';
- $oObject = new OLEObject($src);
-
- $iVal = rand(1, 1000);
- $oObject->setImageRelationId($iVal);
- $this->assertEquals($iVal, $oObject->getImageRelationId());
- }
-}
diff --git a/tests/PhpWord/Element/PreserveTextTest.php b/tests/PhpWord/Element/PreserveTextTest.php
deleted file mode 100644
index 97e49b93df..0000000000
--- a/tests/PhpWord/Element/PreserveTextTest.php
+++ /dev/null
@@ -1,62 +0,0 @@
-assertInstanceOf('PhpOffice\\PhpWord\\Element\\PreserveText', $oPreserveText);
- $this->assertNull($oPreserveText->getText());
- $this->assertNull($oPreserveText->getFontStyle());
- $this->assertNull($oPreserveText->getParagraphStyle());
- }
-
- /**
- * Create new instance with style name
- */
- public function testConstructWithString()
- {
- $oPreserveText = new PreserveText('text', 'styleFont', 'styleParagraph');
- $this->assertEquals(array('text'), $oPreserveText->getText());
- $this->assertEquals('styleFont', $oPreserveText->getFontStyle());
- $this->assertEquals('styleParagraph', $oPreserveText->getParagraphStyle());
- }
-
- /**
- * Create new instance with array
- */
- public function testConstructWithArray()
- {
- $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/RowTest.php b/tests/PhpWord/Element/RowTest.php
deleted file mode 100644
index 3c53450294..0000000000
--- a/tests/PhpWord/Element/RowTest.php
+++ /dev/null
@@ -1,65 +0,0 @@
-assertInstanceOf('PhpOffice\\PhpWord\\Element\\Row', $oRow);
- $this->assertNull($oRow->getHeight());
- $this->assertInternalType('array', $oRow->getCells());
- $this->assertCount(0, $oRow->getCells());
- $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Row', $oRow->getStyle());
- }
-
- /**
- * Create new instance with parameters
- */
- public function testConstructWithParams()
- {
- $iVal = rand(1, 1000);
- $oRow = new Row($iVal, array('borderBottomSize' => 18, 'borderBottomColor' => '0000FF', 'bgColor' => '66BBFF'));
-
- $this->assertEquals($iVal, $oRow->getHeight());
- $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Row', $oRow->getStyle());
- }
-
- /**
- * Add cell
- */
- public function testAddCell()
- {
- $oRow = new Row();
- $element = $oRow->addCell();
-
- $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Cell', $element);
- $this->assertCount(1, $oRow->getCells());
- }
-}
diff --git a/tests/PhpWord/Element/TableTest.php b/tests/PhpWord/Element/TableTest.php
deleted file mode 100644
index 8ae5306c82..0000000000
--- a/tests/PhpWord/Element/TableTest.php
+++ /dev/null
@@ -1,108 +0,0 @@
-assertInstanceOf('PhpOffice\\PhpWord\\Element\\Table', $oTable);
- $this->assertNull($oTable->getStyle());
- $this->assertNull($oTable->getWidth());
- $this->assertEquals(array(), $oTable->getRows());
- $this->assertCount(0, $oTable->getRows());
- }
-
- /**
- * Get style name
- */
- public function testStyleText()
- {
- $oTable = new Table('tableStyle');
-
- $this->assertEquals('tableStyle', $oTable->getStyle());
- }
-
- /**
- * Get style array
- */
- public function testStyleArray()
- {
- $oTable = new Table(array('borderSize' => 6, 'borderColor' => '006699', 'cellMargin' => 80));
-
- $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Table', $oTable->getStyle());
- }
-
- /**
- * Set/get width
- */
- public function testWidth()
- {
- $oTable = new Table();
- $iVal = rand(1, 1000);
- $oTable->setWidth($iVal);
- $this->assertEquals($iVal, $oTable->getWidth());
- }
-
- /**
- * Add/get row
- */
- public function testRow()
- {
- $oTable = new Table();
- $element = $oTable->addRow();
- $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Row', $element);
- $this->assertCount(1, $oTable->getRows());
- }
-
- /**
- * Add cell
- */
- public function testCell()
- {
- $oTable = new Table();
- $oTable->addRow();
- $element = $oTable->addCell();
- $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Cell', $element);
- }
-
- /**
- * Add cell
- */
- public function testCountColumns()
- {
- $oTable = new Table();
- $oTable->addRow();
- $element = $oTable->addCell();
- $this->assertEquals($oTable->countColumns(), 1);
- $element = $oTable->addCell();
- $element = $oTable->addCell();
- $this->assertEquals($oTable->countColumns(), 3);
- }
-}
diff --git a/tests/PhpWord/Element/TextRunTest.php b/tests/PhpWord/Element/TextRunTest.php
deleted file mode 100644
index 2168bcc49a..0000000000
--- a/tests/PhpWord/Element/TextRunTest.php
+++ /dev/null
@@ -1,184 +0,0 @@
-assertInstanceOf('PhpOffice\\PhpWord\\Element\\TextRun', $oTextRun);
- $this->assertCount(0, $oTextRun->getElements());
- $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Paragraph', $oTextRun->getParagraphStyle());
- }
-
- /**
- * New instance with string
- */
- public function testConstructString()
- {
- $oTextRun = new TextRun('pStyle');
-
- $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\TextRun', $oTextRun);
- $this->assertCount(0, $oTextRun->getElements());
- $this->assertEquals('pStyle', $oTextRun->getParagraphStyle());
- }
-
- /**
- * New instance with array
- */
- public function testConstructArray()
- {
- $oTextRun = new TextRun(array('spacing' => 100));
-
- $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\TextRun', $oTextRun);
- $this->assertCount(0, $oTextRun->getElements());
- $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
- */
- public function testAddText()
- {
- $oTextRun = new TextRun();
- $element = $oTextRun->addText('text');
-
- $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Text', $element);
- $this->assertCount(1, $oTextRun->getElements());
- $this->assertEquals('text', $element->getText());
- }
-
- /**
- * Add text non-UTF8
- */
- public function testAddTextNotUTF8()
- {
- $oTextRun = new TextRun();
- $element = $oTextRun->addText(utf8_decode('ééé'));
-
- $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Text', $element);
- $this->assertCount(1, $oTextRun->getElements());
- $this->assertEquals('ééé', $element->getText());
- }
-
- /**
- * Add link
- */
- public function testAddLink()
- {
- $oTextRun = new TextRun();
- $element = $oTextRun->addLink('https://github.com/PHPOffice/PHPWord');
-
- $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Link', $element);
- $this->assertCount(1, $oTextRun->getElements());
- $this->assertEquals('https://github.com/PHPOffice/PHPWord', $element->getSource());
- }
-
- /**
- * Add link with name
- */
- public function testAddLinkWithName()
- {
- $oTextRun = new TextRun();
- $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('PHPWord on GitHub', $element->getText());
- }
-
- /**
- * Add text break
- */
- public function testAddTextBreak()
- {
- $oTextRun = new TextRun();
- $oTextRun->addTextBreak(2);
-
- $this->assertCount(2, $oTextRun->getElements());
- }
-
- /**
- * Add image
- */
- public function testAddImage()
- {
- $src = __DIR__ . '/../_files/images/earth.jpg';
-
- $oTextRun = new TextRun();
- $element = $oTextRun->addImage($src);
-
- $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Image', $element);
- $this->assertCount(1, $oTextRun->getElements());
- }
-
- /**
- * Add footnote
- */
- public function testCreateFootnote()
- {
- $oTextRun = new TextRun();
- $oTextRun->setPhpWord(new PhpWord());
- $element = $oTextRun->addFootnote();
-
- $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/Element/TextTest.php b/tests/PhpWord/Element/TextTest.php
deleted file mode 100644
index 97be7ae5b6..0000000000
--- a/tests/PhpWord/Element/TextTest.php
+++ /dev/null
@@ -1,86 +0,0 @@
-assertInstanceOf('PhpOffice\\PhpWord\\Element\\Text', $oText);
- $this->assertNull($oText->getText());
- $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Font', $oText->getFontStyle());
- $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Paragraph', $oText->getParagraphStyle());
- }
-
- /**
- * Get text
- */
- public function testText()
- {
- $oText = new Text('text');
-
- $this->assertEquals('text', $oText->getText());
- }
-
- /**
- * Get font style
- */
- public function testFont()
- {
- $oText = new Text('text', 'fontStyle');
- $this->assertEquals('fontStyle', $oText->getFontStyle());
-
- $oText->setFontStyle(array('bold' => true, 'italic' => true, 'size' => 16));
- $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Font', $oText->getFontStyle());
- }
-
- /**
- * Get font style as object
- */
- public function testFontObject()
- {
- $font = new Font();
- $oText = new Text('text', $font);
- $this->assertEquals($font, $oText->getFontStyle());
- }
-
- /**
- * Get paragraph style
- */
- public function testParagraph()
- {
- $oText = new Text('text', 'fontStyle', '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/Element/TitleTest.php b/tests/PhpWord/Element/TitleTest.php
deleted file mode 100644
index 6ef87c3e8e..0000000000
--- a/tests/PhpWord/Element/TitleTest.php
+++ /dev/null
@@ -1,69 +0,0 @@
-assertInstanceOf('PhpOffice\\PhpWord\\Element\\Title', $oTitle);
- $this->assertEquals('text', $oTitle->getText());
- }
-
- /**
- * Get style null
- */
- public function testStyleNull()
- {
- $oTitle = new Title('text');
-
- $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/IOFactoryTest.php b/tests/PhpWord/IOFactoryTest.php
deleted file mode 100644
index 4a59e7022a..0000000000
--- a/tests/PhpWord/IOFactoryTest.php
+++ /dev/null
@@ -1,80 +0,0 @@
-assertInstanceOf(
- 'PhpOffice\\PhpWord\\Writer\\Word2007',
- IOFactory::createWriter(new PhpWord(), 'Word2007')
- );
- }
-
- /**
- * Create non-existing writer
- *
- * @expectedException \PhpOffice\PhpWord\Exception\Exception
- */
- public function testNonexistentWriterCanNotBeCreated()
- {
- IOFactory::createWriter(new PhpWord(), 'Word2006');
- }
-
- /**
- * Create existing reader
- */
- public function testExistingReaderCanBeCreated()
- {
- $this->assertInstanceOf(
- 'PhpOffice\\PhpWord\\Reader\\Word2007',
- IOFactory::createReader('Word2007')
- );
- }
-
- /**
- * Create non-existing reader
- *
- * @expectedException \PhpOffice\PhpWord\Exception\Exception
- */
- public function testNonexistentReaderCanNotBeCreated()
- {
- IOFactory::createReader('Word2006');
- }
-
- /**
- * Load document
- */
- public function testLoad()
- {
- $file = __DIR__ . '/_files/templates/blank.docx';
- $this->assertInstanceOf(
- 'PhpOffice\\PhpWord\\PhpWord',
- IOFactory::load($file)
- );
- }
-}
diff --git a/tests/PhpWord/Metadata/DocInfoTest.php b/tests/PhpWord/Metadata/DocInfoTest.php
deleted file mode 100644
index 25a323d2f2..0000000000
--- a/tests/PhpWord/Metadata/DocInfoTest.php
+++ /dev/null
@@ -1,226 +0,0 @@
-setCreator();
- $this->assertEquals('', $oProperties->getCreator());
-
- $oProperties->setCreator('AAA');
- $this->assertEquals('AAA', $oProperties->getCreator());
- }
-
- /**
- * Last modified by
- */
- public function testLastModifiedBy()
- {
- $oProperties = new DocInfo();
- $oProperties->setLastModifiedBy();
- $this->assertEquals('', $oProperties->getLastModifiedBy());
-
- $oProperties->setLastModifiedBy('AAA');
- $this->assertEquals('AAA', $oProperties->getLastModifiedBy());
- }
-
- /**
- * Created
- */
- public function testCreated()
- {
- $oProperties = new DocInfo();
- $oProperties->setCreated();
- $this->assertEquals(time(), $oProperties->getCreated());
-
- $iTime = time() + 3600;
- $oProperties->setCreated($iTime);
- $this->assertEquals($iTime, $oProperties->getCreated());
- }
-
- /**
- * Modified
- */
- public function testModified()
- {
- $oProperties = new DocInfo();
- $oProperties->setModified();
- $this->assertEquals(time(), $oProperties->getModified());
-
- $iTime = time() + 3600;
- $oProperties->setModified($iTime);
- $this->assertEquals($iTime, $oProperties->getModified());
- }
-
- /**
- * Title
- */
- public function testTitle()
- {
- $oProperties = new DocInfo();
- $oProperties->setTitle();
- $this->assertEquals('', $oProperties->getTitle());
-
- $oProperties->setTitle('AAA');
- $this->assertEquals('AAA', $oProperties->getTitle());
- }
-
- /**
- * Description
- */
- public function testDescription()
- {
- $oProperties = new DocInfo();
- $oProperties->setDescription();
- $this->assertEquals('', $oProperties->getDescription());
-
- $oProperties->setDescription('AAA');
- $this->assertEquals('AAA', $oProperties->getDescription());
- }
-
- /**
- * Subject
- */
- public function testSubject()
- {
- $oProperties = new DocInfo();
- $oProperties->setSubject();
- $this->assertEquals('', $oProperties->getSubject());
-
- $oProperties->setSubject('AAA');
- $this->assertEquals('AAA', $oProperties->getSubject());
- }
-
- /**
- * Keywords
- */
- public function testKeywords()
- {
- $oProperties = new DocInfo();
- $oProperties->setKeywords();
- $this->assertEquals('', $oProperties->getKeywords());
-
- $oProperties->setKeywords('AAA');
- $this->assertEquals('AAA', $oProperties->getKeywords());
- }
-
- /**
- * Category
- */
- public function testCategory()
- {
- $oProperties = new DocInfo();
- $oProperties->setCategory();
- $this->assertEquals('', $oProperties->getCategory());
-
- $oProperties->setCategory('AAA');
- $this->assertEquals('AAA', $oProperties->getCategory());
- }
-
- /**
- * Company
- */
- public function testCompany()
- {
- $oProperties = new DocInfo();
- $oProperties->setCompany();
- $this->assertEquals('', $oProperties->getCompany());
-
- $oProperties->setCompany('AAA');
- $this->assertEquals('AAA', $oProperties->getCompany());
- }
-
- /**
- * Manager
- */
- public function testManager()
- {
- $oProperties = new DocInfo();
- $oProperties->setManager();
- $this->assertEquals('', $oProperties->getManager());
-
- $oProperties->setManager('AAA');
- $this->assertEquals('AAA', $oProperties->getManager());
- }
-
- /**
- * Custom properties
- */
- public function testCustomProperty()
- {
- $oProperties = new DocInfo();
- $oProperties->setCustomProperty('key1', null);
- $oProperties->setCustomProperty('key2', true);
- $oProperties->setCustomProperty('key3', 3);
- $oProperties->setCustomProperty('key4', 4.4);
- $oProperties->setCustomProperty('key5', 'value5');
- $this->assertEquals(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->assertNull($oProperties->getCustomPropertyValue('key6'));
- $this->assertTrue($oProperties->isCustomPropertySet('key5'));
- $this->assertNotTrue($oProperties->isCustomPropertySet('key6'));
- $this->assertEquals(array('key1', 'key2', 'key3', 'key4', 'key5'), $oProperties->getCustomProperties());
- }
-
- /**
- * Convert property
- */
- public function testConvertProperty()
- {
- $this->assertEquals('', DocInfo::convertProperty('a', 'empty'));
- $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->assertTrue(DocInfo::convertProperty('true', 'bool'));
- $this->assertNotTrue(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(''));
- }
-}
diff --git a/tests/PhpWord/Metadata/SettingsTest.php b/tests/PhpWord/Metadata/SettingsTest.php
deleted file mode 100644
index 9670f1d992..0000000000
--- a/tests/PhpWord/Metadata/SettingsTest.php
+++ /dev/null
@@ -1,229 +0,0 @@
-setEvenAndOddHeaders(true);
- $this->assertTrue($oSettings->hasEvenAndOddHeaders());
- }
-
- /**
- * HideGrammaticalErrors
- */
- public function testHideGrammaticalErrors()
- {
- $oSettings = new Settings();
- $oSettings->setHideGrammaticalErrors(true);
- $this->assertTrue($oSettings->hasHideGrammaticalErrors());
- }
-
- /**
- * HideSpellingErrors
- */
- public function testHideSpellingErrors()
- {
- $oSettings = new Settings();
- $oSettings->setHideSpellingErrors(true);
- $this->assertTrue($oSettings->hasHideSpellingErrors());
- }
-
- /**
- * DocumentProtection
- */
- public function testDocumentProtection()
- {
- $oSettings = new Settings();
- $oSettings->setDocumentProtection(new Protection('trackedChanges'));
- $this->assertNotNull($oSettings->getDocumentProtection());
-
- $this->assertEquals('trackedChanges', $oSettings->getDocumentProtection()->getEditing());
- }
-
- /**
- * Test setting an invalid salt
- * @expectedException \InvalidArgumentException
- */
- public function testInvalidSalt()
- {
- $protection = new Protection();
- $protection->setSalt('123');
- }
-
- /**
- * TrackRevistions
- */
- public function testTrackRevisions()
- {
- $oSettings = new Settings();
- $oSettings->setTrackRevisions(true);
- $this->assertTrue($oSettings->hasTrackRevisions());
- }
-
- /**
- * DoNotTrackFormatting
- */
- public function testDoNotTrackFormatting()
- {
- $oSettings = new Settings();
- $oSettings->setDoNotTrackFormatting(true);
- $this->assertTrue($oSettings->hasDoNotTrackFormatting());
- }
-
- /**
- * DoNotTrackMoves
- */
- public function testDoNotTrackMoves()
- {
- $oSettings = new Settings();
- $oSettings->setDoNotTrackMoves(true);
- $this->assertTrue($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());
- }
-
- /**
- * @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
- */
- 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());
- }
-
- /**
- * Test Update Fields on update
- */
- public function testUpdateFields()
- {
- $oSettings = new Settings();
- $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
deleted file mode 100644
index d818e0f8bb..0000000000
--- a/tests/PhpWord/PhpWordTest.php
+++ /dev/null
@@ -1,228 +0,0 @@
-assertEquals(new DocInfo(), $phpWord->getDocInfo());
- $this->assertEquals(Settings::DEFAULT_FONT_NAME, $phpWord->getDefaultFontName());
- $this->assertEquals(Settings::DEFAULT_FONT_SIZE, $phpWord->getDefaultFontSize());
- }
-
- /**
- * Test create/get section
- */
- public function testCreateGetSections()
- {
- $phpWord = new PhpWord();
- $phpWord->addSection();
- $this->assertCount(1, $phpWord->getSections());
- }
-
- /**
- * Test set/get default font name
- */
- public function testSetGetDefaultFontName()
- {
- $phpWord = new PhpWord();
- $fontName = 'Times New Roman';
- $this->assertEquals(Settings::DEFAULT_FONT_NAME, $phpWord->getDefaultFontName());
- $phpWord->setDefaultFontName($fontName);
- $this->assertEquals($fontName, $phpWord->getDefaultFontName());
- }
-
- /**
- * Test set/get default font size
- */
- public function testSetGetDefaultFontSize()
- {
- $phpWord = new PhpWord();
- $fontSize = 16;
- $this->assertEquals(Settings::DEFAULT_FONT_SIZE, $phpWord->getDefaultFontSize());
- $phpWord->setDefaultFontSize($fontSize);
- $this->assertEquals($fontSize, $phpWord->getDefaultFontSize());
- }
-
- /**
- * Test set default paragraph style
- */
- public function testSetDefaultParagraphStyle()
- {
- $phpWord = new PhpWord();
- $phpWord->setDefaultParagraphStyle(array());
- $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Paragraph', Style::getStyle('Normal'));
- }
-
- /**
- * Test add styles
- */
- public function testAddStyles()
- {
- $phpWord = new PhpWord();
- $styles = array(
- 'Paragraph' => 'Paragraph',
- 'Font' => 'Font',
- 'Table' => 'Table',
- 'Link' => 'Font',
- );
- foreach ($styles as $key => $value) {
- $method = "add{$key}Style";
- $styleId = "{$key} Style";
- $phpWord->$method($styleId, array());
- $this->assertInstanceOf("PhpOffice\\PhpWord\\Style\\{$value}", Style::getStyle($styleId));
- }
- }
-
- /**
- * Test add title style
- */
- public function testAddTitleStyle()
- {
- $phpWord = new PhpWord();
- $titleLevel = 1;
- $titleName = "Heading_{$titleLevel}";
- $phpWord->addTitleStyle($titleLevel, array());
- $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Font', Style::getStyle($titleName));
- }
-
- /**
- * Test load template
- *
- * @deprecated 0.12.0
- */
- public function testLoadTemplate()
- {
- $templateFqfn = __DIR__ . '/_files/templates/blank.docx';
-
- $phpWord = new PhpWord();
- $this->assertInstanceOf(
- 'PhpOffice\\PhpWord\\TemplateProcessor',
- $phpWord->loadTemplate($templateFqfn)
- );
- }
-
- /**
- * Test load template exception
- *
- * @deprecated 0.12.0
- *
- * @expectedException \PhpOffice\PhpWord\Exception\Exception
- */
- public function testLoadTemplateException()
- {
- $templateFqfn = implode(
- DIRECTORY_SEPARATOR,
- array(PHPWORD_TESTS_BASE_DIR, 'PhpWord', 'Tests', '_files', 'templates', 'blanks.docx')
- );
- $phpWord = new PhpWord();
- $phpWord->loadTemplate($templateFqfn);
- }
-
- /**
- * Test save
- */
- public function testSave()
- {
- $this->setOutputCallback(function () {
- });
- $phpWord = new PhpWord();
- $section = $phpWord->addSection();
- $section->addText('Hello world!');
-
- $this->assertTrue($phpWord->save('test.docx', 'Word2007', true));
- }
-
- /**
- * Test calling undefined method
- *
- * @expectedException \BadMethodCallException
- * @expectedExceptionMessage is not defined
- */
- public function testCallUndefinedMethod()
- {
- $phpWord = new PhpWord();
- $phpWord->undefinedMethod();
- }
-
- /**
- * @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/MsDocTest.php b/tests/PhpWord/Reader/MsDocTest.php
deleted file mode 100644
index 3ce3993977..0000000000
--- a/tests/PhpWord/Reader/MsDocTest.php
+++ /dev/null
@@ -1,79 +0,0 @@
-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);
- }
-
- /**
- * 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/Reader/Word2007/ElementTest.php b/tests/PhpWord/Reader/Word2007/ElementTest.php
deleted file mode 100644
index cb72ef9f0a..0000000000
--- a/tests/PhpWord/Reader/Word2007/ElementTest.php
+++ /dev/null
@@ -1,275 +0,0 @@
-
-
-
- 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\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());
- }
-
- /**
- * Test reading of textbreak
- */
- public function testReadListItemRunWithFormatting()
- {
- $documentXml = '
-
-
-
-
-
-
-
- Two
-
-
- with
-
-
-
-
-
- bold
-
- ';
-
- $phpWord = $this->getDocumentFromString(array('document' => $documentXml));
-
- $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 = $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 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
- */
- public function testReadTab()
- {
- $documentXml = '
-
- One
-
- Two
-
- ';
-
- $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('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());
- }
-
- /**
- * 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());
- }
-
- /**
- * 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/Word2007/StyleTest.php b/tests/PhpWord/Reader/Word2007/StyleTest.php
deleted file mode 100644
index a7308f1a16..0000000000
--- a/tests/PhpWord/Reader/Word2007/StyleTest.php
+++ /dev/null
@@ -1,229 +0,0 @@
-
-
-
-
- ';
-
- $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->assertEquals(Table::LAYOUT_FIXED, $elements[0]->getStyle()->getLayout());
- }
-
- /**
- * Test reading of cell spacing
- */
- public function testReadCellSpacing()
- {
- $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->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
- */
- public function testReadPosition()
- {
- $documentXml = '
-
-
-
-
- This text is lowered
-
- ';
-
- $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->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());
- }
-
- 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 = '
-
-
-
-
- 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());
- }
-
- public function testReadHeading()
- {
- Style::resetStyles();
-
- $documentXml = '
-
-
-
-
-
-
-
-
-
-
-
-
- ';
-
- $name = 'Heading_1';
-
- $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/Reader/Word2007Test.php b/tests/PhpWord/Reader/Word2007Test.php
deleted file mode 100644
index 6d660ce5ef..0000000000
--- a/tests/PhpWord/Reader/Word2007Test.php
+++ /dev/null
@@ -1,81 +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'));
- }
-}
diff --git a/tests/PhpWord/SettingsTest.php b/tests/PhpWord/SettingsTest.php
deleted file mode 100644
index afe5954969..0000000000
--- a/tests/PhpWord/SettingsTest.php
+++ /dev/null
@@ -1,140 +0,0 @@
-assertTrue(Settings::hasCompatibility());
- $this->assertTrue(Settings::setCompatibility(false));
- $this->assertFalse(Settings::hasCompatibility());
- }
-
- /**
- * Test set/get zip class
- */
- public function testSetGetZipClass()
- {
- $this->assertEquals(Settings::ZIPARCHIVE, Settings::getZipClass());
- $this->assertTrue(Settings::setZipClass(Settings::PCLZIP));
- $this->assertFalse(Settings::setZipClass('foo'));
- }
-
- /**
- * Test set/get PDF renderer
- */
- public function testSetGetPdfRenderer()
- {
- $domPdfPath = realpath(PHPWORD_TESTS_BASE_DIR . '/../vendor/dompdf/dompdf');
-
- $this->assertFalse(Settings::setPdfRenderer('FOO', 'dummy/path'));
- $this->assertTrue(Settings::setPdfRenderer(Settings::PDF_RENDERER_DOMPDF, $domPdfPath));
- $this->assertEquals(Settings::PDF_RENDERER_DOMPDF, Settings::getPdfRendererName());
- $this->assertEquals($domPdfPath, Settings::getPdfRendererPath());
- $this->assertFalse(Settings::setPdfRendererPath('dummy/path'));
- }
-
- /**
- * Test set/get measurement unit
- */
- public function testSetGetMeasurementUnit()
- {
- $this->assertEquals(Settings::UNIT_TWIP, Settings::getMeasurementUnit());
- $this->assertTrue(Settings::setMeasurementUnit(Settings::UNIT_INCH));
- $this->assertFalse(Settings::setMeasurementUnit('foo'));
- }
-
- /**
- * @covers ::getTempDir
- * @test
- */
- public function testPhpTempDirIsUsedByDefault()
- {
- $this->assertEquals(sys_get_temp_dir(), Settings::getTempDir());
- }
-
- /**
- * @covers ::setTempDir
- * @covers ::getTempDir
- * @depends testPhpTempDirIsUsedByDefault
- * @test
- */
- public function testTempDirCanBeSet()
- {
- $userDefinedTempDir = 'C:\PhpWordTemp';
- Settings::setTempDir($userDefinedTempDir);
- $currentTempDir = Settings::getTempDir();
- $this->assertEquals($userDefinedTempDir, $currentTempDir);
- $this->assertNotEquals(sys_get_temp_dir(), $currentTempDir);
- }
-
- /**
- * Test set/get default font name
- */
- public function testSetGetDefaultFontName()
- {
- $this->assertEquals(Settings::DEFAULT_FONT_NAME, Settings::getDefaultFontName());
- $this->assertTrue(Settings::setDefaultFontName('Times New Roman'));
- $this->assertFalse(Settings::setDefaultFontName(' '));
- }
-
- /**
- * Test set/get default font size
- */
- public function testSetGetDefaultFontSize()
- {
- $this->assertEquals(Settings::DEFAULT_FONT_SIZE, Settings::getDefaultFontSize());
- $this->assertTrue(Settings::setDefaultFontSize(12));
- $this->assertFalse(Settings::setDefaultFontSize(null));
- }
-
- /**
- * Test load config
- */
- public function testLoadConfig()
- {
- $expected = array(
- 'compatibility' => true,
- 'zipClass' => 'ZipArchive',
- 'pdfRendererName' => 'DomPDF',
- 'pdfRendererPath' => '',
- 'defaultFontName' => 'Arial',
- 'defaultFontSize' => 10,
- 'outputEscapingEnabled' => false,
- );
-
- // Test default value
- $this->assertEquals($expected, Settings::loadConfig());
-
- // Test with valid file
- $this->assertEquals($expected, Settings::loadConfig(__DIR__ . '/../../phpword.ini.dist'));
-
- // Test with invalid file
- $this->assertEmpty(Settings::loadConfig(__DIR__ . '/../../phpunit.xml.dist'));
- }
-}
diff --git a/tests/PhpWord/Shared/ConverterTest.php b/tests/PhpWord/Shared/ConverterTest.php
deleted file mode 100644
index 15be8ec12a..0000000000
--- a/tests/PhpWord/Shared/ConverterTest.php
+++ /dev/null
@@ -1,139 +0,0 @@
-assertEquals($value / 2.54 * 1440, $result);
-
- $result = Converter::cmToInch($value);
- $this->assertEquals($value / 2.54, $result);
-
- $result = Converter::cmToPixel($value);
- $this->assertEquals($value / 2.54 * 96, $result);
-
- $result = Converter::cmToPoint($value);
- $this->assertEquals($value / 2.54 * 72, $result);
-
- $result = Converter::cmToEmu($value);
- $this->assertEquals(round($value / 2.54 * 96 * 9525), $result);
-
- $result = Converter::inchToTwip($value);
- $this->assertEquals($value * 1440, $result);
-
- $result = Converter::inchToCm($value);
- $this->assertEquals($value * 2.54, $result);
-
- $result = Converter::inchToPixel($value);
- $this->assertEquals($value * 96, $result);
-
- $result = Converter::inchToPoint($value);
- $this->assertEquals($value * 72, $result);
-
- $result = Converter::inchToEmu($value);
- $this->assertEquals(round($value * 96 * 9525), $result);
-
- $result = Converter::pixelToTwip($value);
- $this->assertEquals($value / 96 * 1440, $result);
-
- $result = Converter::pixelToCm($value);
- $this->assertEquals($value / 96 * 2.54, $result);
-
- $result = Converter::pixelToPoint($value);
- $this->assertEquals($value / 96 * 72, $result);
-
- $result = Converter::pixelToEmu($value);
- $this->assertEquals(round($value * 9525), $result);
-
- $result = Converter::pointToTwip($value);
- $this->assertEquals($value * 20, $result);
-
- $result = Converter::pointToCm($value);
- $this->assertEquals($value * 0.035277778, $result, '', 0.00001);
-
- $result = Converter::pointToPixel($value);
- $this->assertEquals($value / 72 * 96, $result);
-
- $result = Converter::pointToEmu($value);
- $this->assertEquals(round($value / 72 * 96 * 9525), $result);
-
- $result = Converter::emuToPixel($value);
- $this->assertEquals(round($value / 9525), $result);
-
- $result = Converter::picaToPoint($value);
- $this->assertEquals($value / 6 * 72, $result, '', 0.00001);
-
- $result = Converter::degreeToAngle($value);
- $this->assertEquals((int) round($value * 60000), $result);
-
- $result = Converter::angleToDegree($value);
- $this->assertEquals(round($value / 60000), $result);
- }
- }
-
- /**
- * Test htmlToRGB()
- */
- public function testHtmlToRGB()
- {
- // Prepare test values [ original, expected ]
- $values = array();
- $values[] = array('#FF99DD', array(255, 153, 221)); // With #
- $values[] = array('FF99DD', array(255, 153, 221)); // 6 characters
- $values[] = array('F9D', array(255, 153, 221)); // 3 characters
- $values[] = array('0F9D', false); // 4 characters
- // Conduct test
- foreach ($values as $value) {
- $result = Converter::htmlToRgb($value[0]);
- $this->assertEquals($value[1], $result);
- }
- }
-
- /**
- * Test css size to point
- */
- public function testCssSizeParser()
- {
- $this->assertNull(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'));
- $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/Style/AbstractStyleTest.php b/tests/PhpWord/Style/AbstractStyleTest.php
deleted file mode 100644
index 7ec272bb9b..0000000000
--- a/tests/PhpWord/Style/AbstractStyleTest.php
+++ /dev/null
@@ -1,92 +0,0 @@
-getMockForAbstractClass('\PhpOffice\PhpWord\Style\AbstractStyle');
- $stub->setStyleByArray(array('index' => 1));
-
- $this->assertEquals(1, $stub->getIndex());
- }
-
- /**
- * Test setBoolVal, setIntVal, setFloatVal, setEnumVal with normal value
- */
- public function testSetValNormal()
- {
- $stub = $this->getMockForAbstractClass('\PhpOffice\PhpWord\Style\AbstractStyle');
-
- $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)));
- $this->assertEquals('a', self::callProtectedMethod($stub, 'setEnumVal', array('a', array('a', 'b'), 'b')));
- }
-
- /**
- * Test setBoolVal, setIntVal, setFloatVal, setEnumVal with default value
- */
- public function testSetValDefault()
- {
- $stub = $this->getMockForAbstractClass('\PhpOffice\PhpWord\Style\AbstractStyle');
-
- $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')));
- }
-
- /**
- * Test setEnumVal exception
- *
- * @expectedException \InvalidArgumentException
- */
- public function testSetValEnumException()
- {
- $stub = $this->getMockForAbstractClass('\PhpOffice\PhpWord\Style\AbstractStyle');
-
- $this->assertEquals('b', self::callProtectedMethod($stub, 'setEnumVal', array('z', array('a', 'b'), 'b')));
- }
-
- /**
- * Helper function to call protected method
- *
- * @param mixed $object
- * @param string $method
- * @param array $args
- */
- 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
deleted file mode 100644
index 3c31a45794..0000000000
--- a/tests/PhpWord/Style/CellTest.php
+++ /dev/null
@@ -1,90 +0,0 @@
- 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) {
- $set = "set{$key}";
- $get = "get{$key}";
-
- $this->assertNull($object->$get()); // Init with null value
-
- $object->$set($value);
-
- $this->assertEquals($value, $object->$get());
- }
- }
-
- /**
- * Test border color
- */
- public function testBorderColor()
- {
- $object = new Cell();
-
- $value = 'FF0000';
-
- $object->setStyleValue('borderColor', $value);
- $expected = array($value, $value, $value, $value);
- $this->assertEquals($expected, $object->getBorderColor());
- }
-
- /**
- * Test border size
- */
- public function testBorderSize()
- {
- $object = new Cell();
-
- $value = 120;
- $expected = array($value, $value, $value, $value);
- $object->setStyleValue('borderSize', $value);
- $this->assertEquals($expected, $object->getBorderSize());
- }
-}
diff --git a/tests/PhpWord/Style/ChartTest.php b/tests/PhpWord/Style/ChartTest.php
deleted file mode 100644
index 9929a8f5a7..0000000000
--- a/tests/PhpWord/Style/ChartTest.php
+++ /dev/null
@@ -1,188 +0,0 @@
-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');
- }
-}
diff --git a/tests/PhpWord/Style/FontTest.php b/tests/PhpWord/Style/FontTest.php
deleted file mode 100644
index 84916fc277..0000000000
--- a/tests/PhpWord/Style/FontTest.php
+++ /dev/null
@@ -1,193 +0,0 @@
- Jc::BOTH));
-
- $this->assertEquals('text', $object->getStyleType());
- $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Paragraph', $object->getParagraphStyle());
- $this->assertInternalType('array', $object->getStyleValues());
- }
-
- /**
- * Test setting style values with null or empty value
- */
- 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,
- 'doubleStrikethrough' => false,
- 'smallCaps' => false,
- 'allCaps' => false,
- 'rtl' => false,
- 'fgColor' => null,
- 'bgColor' => null,
- 'scale' => null,
- 'spacing' => null,
- 'kerning' => null,
- 'lang' => null,
- 'hidden' => false,
- );
- foreach ($attributes as $key => $default) {
- $get = is_bool($default) ? "is{$key}" : "get{$key}";
- $this->assertEquals($default, $object->$get());
- $object->setStyleValue($key, null);
- $this->assertEquals($default, $object->$get());
- $object->setStyleValue($key, '');
- $this->assertEquals($default, $object->$get());
- }
- }
-
- /**
- * Test setting style values with normal value
- */
- 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,
- 'doubleStrikethrough' => false,
- 'smallCaps' => true,
- 'allCaps' => false,
- 'fgColor' => Font::FGCOLOR_YELLOW,
- 'bgColor' => 'FFFF00',
- 'lineHeight' => 2,
- 'scale' => 150,
- 'spacing' => 240,
- 'kerning' => 10,
- 'rtl' => true,
- 'noProof' => true,
- 'lang' => new Language(Language::EN_US),
- 'hidden' => true,
- );
- $object->setStyleByArray($attributes);
- foreach ($attributes as $key => $value) {
- $get = is_bool($value) ? "is{$key}" : "get{$key}";
- $this->assertEquals($value, $object->$get());
- }
- }
-
- /**
- * Test set line height
- */
- public function testLineHeight()
- {
- $phpWord = new PhpWord();
- $section = $phpWord->addSection();
-
- // Test style array
- $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');
-
- $lineHeight = $element->getAttribute('w:line');
- $lineRule = $element->getAttribute('w:lineRule');
-
- $this->assertEquals(480, $lineHeight);
- $this->assertEquals('auto', $lineRule);
-
- // Test setter
- $text->getFontStyle()->setLineHeight(3.0);
- $doc = TestHelperDOCX::getDocument($phpWord);
- $element = $doc->getElement('/w:document/w:body/w:p/w:pPr/w:spacing');
-
- $lineHeight = $element->getAttribute('w:line');
- $lineRule = $element->getAttribute('w:lineRule');
-
- $this->assertEquals(720, $lineHeight);
- $this->assertEquals('auto', $lineRule);
- }
-
- /**
- * Test line height floatval
- */
- public function testLineHeightFloatval()
- {
- $object = new Font(null, array('alignment' => Jc::CENTER));
- $object->setLineHeight('1.5pt');
- $this->assertEquals(1.5, $object->getLineHeight());
- }
-
- /**
- * Test line height exception by using nonnumeric value
- *
- * @expectedException \PhpOffice\PhpWord\Exception\InvalidStyleException
- */
- 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/ImageTest.php b/tests/PhpWord/Style/ImageTest.php
deleted file mode 100644
index 1d43d92152..0000000000
--- a/tests/PhpWord/Style/ImageTest.php
+++ /dev/null
@@ -1,98 +0,0 @@
- 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}";
- $get = "get{$key}";
- $object->$set($value);
- $this->assertEquals($value, $object->$get());
- }
- }
-
- /**
- * Test setStyleValue method
- */
- public function testSetStyleValue()
- {
- $object = new Image();
-
- $properties = array(
- '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}";
- $object->setStyleValue("{$key}", $value);
- $this->assertEquals($value, $object->$get());
- }
- }
-
- /**
- * Test setWrappingStyle exception
- *
- * @expectedException \InvalidArgumentException
- */
- public function testSetWrappingStyleException()
- {
- $object = new Image();
- $object->setWrappingStyle('foo');
- }
-}
diff --git a/tests/PhpWord/Style/LanguageTest.php b/tests/PhpWord/Style/LanguageTest.php
deleted file mode 100644
index 3bf516f8ae..0000000000
--- a/tests/PhpWord/Style/LanguageTest.php
+++ /dev/null
@@ -1,77 +0,0 @@
- 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('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());
- }
-}
diff --git a/tests/PhpWord/Style/LineNumberingTest.php b/tests/PhpWord/Style/LineNumberingTest.php
deleted file mode 100644
index 0d3f4e0563..0000000000
--- a/tests/PhpWord/Style/LineNumberingTest.php
+++ /dev/null
@@ -1,51 +0,0 @@
- array(1, 2),
- 'increment' => array(1, 10),
- 'distance' => array(null, 10),
- 'restart' => array(null, 'continuous'),
- );
- 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
- }
- }
-}
diff --git a/tests/PhpWord/Style/LineTest.php b/tests/PhpWord/Style/LineTest.php
deleted file mode 100644
index fba09f708d..0000000000
--- a/tests/PhpWord/Style/LineTest.php
+++ /dev/null
@@ -1,149 +0,0 @@
- \PhpOffice\PhpWord\Style\Line::CONNECTOR_TYPE_STRAIGHT,
- 'beginArrow' => \PhpOffice\PhpWord\Style\Line::ARROW_STYLE_BLOCK,
- 'endArrow' => \PhpOffice\PhpWord\Style\Line::ARROW_STYLE_OVAL,
- 'dash' => \PhpOffice\PhpWord\Style\Line::DASH_STYLE_LONG_DASH_DOT_DOT,
- 'weight' => 10,
- 'color' => 'red',
- );
- foreach ($properties as $key => $value) {
- $set = "set{$key}";
- $get = "get{$key}";
- $object->$set($value);
- $this->assertEquals($value, $object->$get());
- }
- }
-
- /**
- * Test setStyleValue method
- */
- public function testSetStyleValue()
- {
- $object = new Line();
-
- $properties = array(
- 'connectorType' => \PhpOffice\PhpWord\Style\Line::CONNECTOR_TYPE_STRAIGHT,
- 'beginArrow' => \PhpOffice\PhpWord\Style\Line::ARROW_STYLE_BLOCK,
- 'endArrow' => \PhpOffice\PhpWord\Style\Line::ARROW_STYLE_OVAL,
- 'dash' => \PhpOffice\PhpWord\Style\Line::DASH_STYLE_LONG_DASH_DOT_DOT,
- 'weight' => 10,
- 'color' => 'red',
- );
- foreach ($properties as $key => $value) {
- $get = "get{$key}";
- $object->setStyleValue("{$key}", $value);
- $this->assertEquals($value, $object->$get());
- }
- }
-
- /**
- * Test set/get flip
- */
- public function testSetGetFlip()
- {
- $expected = true;
- $object = new Line();
- $object->setFlip($expected);
- $this->assertEquals($expected, $object->isFlip());
- }
-
- /**
- * Test set/get connectorType
- */
- public function testSetGetConnectorType()
- {
- $expected = \PhpOffice\PhpWord\Style\Line::CONNECTOR_TYPE_STRAIGHT;
- $object = new Line();
- $object->setConnectorType($expected);
- $this->assertEquals($expected, $object->getConnectorType());
- }
-
- /**
- * Test set/get weight
- */
- public function testSetGetWeight()
- {
- $expected = 10;
- $object = new Line();
- $object->setWeight($expected);
- $this->assertEquals($expected, $object->getWeight());
- }
-
- /**
- * Test set/get color
- */
- public function testSetGetColor()
- {
- $expected = 'red';
- $object = new Line();
- $object->setColor($expected);
- $this->assertEquals($expected, $object->getColor());
- }
-
- /**
- * Test set/get dash
- */
- public function testSetGetDash()
- {
- $expected = \PhpOffice\PhpWord\Style\Line::DASH_STYLE_LONG_DASH_DOT_DOT;
- $object = new Line();
- $object->setDash($expected);
- $this->assertEquals($expected, $object->getDash());
- }
-
- /**
- * Test set/get beginArrow
- */
- public function testSetGetBeginArrow()
- {
- $expected = \PhpOffice\PhpWord\Style\Line::ARROW_STYLE_BLOCK;
- $object = new Line();
- $object->setBeginArrow($expected);
- $this->assertEquals($expected, $object->getBeginArrow());
- }
-
- /**
- * Test set/get endArrow
- */
- public function testSetGetEndArrow()
- {
- $expected = \PhpOffice\PhpWord\Style\Line::ARROW_STYLE_CLASSIC;
- $object = new Line();
- $object->setEndArrow($expected);
- $this->assertEquals($expected, $object->getEndArrow());
- }
-}
diff --git a/tests/PhpWord/Style/NumberingTest.php b/tests/PhpWord/Style/NumberingTest.php
deleted file mode 100644
index 2090f9f6fc..0000000000
--- a/tests/PhpWord/Style/NumberingTest.php
+++ /dev/null
@@ -1,59 +0,0 @@
- array(null, 1),
- 'type' => array(null, 'singleLevel'),
- );
- 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 get level
- */
- public function testGetLevels()
- {
- $object = new Numbering();
-
- $this->assertEmpty($object->getLevels());
- }
-}
diff --git a/tests/PhpWord/Style/ParagraphTest.php b/tests/PhpWord/Style/ParagraphTest.php
deleted file mode 100644
index 4fa0ef5a70..0000000000
--- a/tests/PhpWord/Style/ParagraphTest.php
+++ /dev/null
@@ -1,188 +0,0 @@
- true,
- 'keepNext' => false,
- 'keepLines' => false,
- 'pageBreakBefore' => false,
- 'contextualSpacing' => false,
- );
- foreach ($attributes as $key => $default) {
- $get = $this->findGetter($key, $default, $object);
- $object->setStyleValue($key, null);
- $this->assertEquals($default, $object->$get());
- $object->setStyleValue($key, '');
- $this->assertEquals($default, $object->$get());
- }
- }
-
- /**
- * Test setting style values with normal value
- */
- 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,
- 'suppressAutoHyphens' => true,
- );
- foreach ($attributes as $key => $value) {
- $get = $this->findGetter($key, $value, $object);
- $object->setStyleValue("$key", $value);
- if ('indent' == $key || 'hanging' == $key) {
- $value = $value * 720;
- }
- $this->assertEquals($value, $object->$get());
- }
- }
-
- private function findGetter($key, $value, $object)
- {
- if (is_bool($value)) {
- if (method_exists($object, "is{$key}")) {
- return "is{$key}";
- } elseif (method_exists($object, "has{$key}")) {
- return "has{$key}";
- }
- }
-
- return "get{$key}";
- }
-
- /**
- * Test get null style value
- */
- public function testGetNullStyleValue()
- {
- $object = new Paragraph();
-
- $attributes = array('spacing', 'indent', 'hanging', 'spaceBefore', 'spaceAfter', 'textAlignment');
- foreach ($attributes as $key) {
- $get = $this->findGetter($key, null, $object);
- $this->assertNull($object->$get());
- }
- }
-
- /**
- * Test tabs
- */
- public function testTabs()
- {
- $object = new Paragraph();
- $object->setTabs(array(new Tab('left', 1550), new Tab('right', 5300)));
- $this->assertCount(2, $object->getTabs());
- }
-
- /**
- * Line height
- */
- public function testLineHeight()
- {
- $phpWord = new PhpWord();
- $section = $phpWord->addSection();
-
- // Test style array
- $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');
-
- $lineHeight = $element->getAttribute('w:line');
- $lineRule = $element->getAttribute('w:lineRule');
-
- $this->assertEquals(480, $lineHeight);
- $this->assertEquals('auto', $lineRule);
-
- // Test setter
- $text->getParagraphStyle()->setLineHeight(3.0);
- $doc = TestHelperDOCX::getDocument($phpWord);
- $element = $doc->getElement('/w:document/w:body/w:p/w:pPr/w:spacing');
-
- $lineHeight = $element->getAttribute('w:line');
- $lineRule = $element->getAttribute('w:lineRule');
-
- $this->assertEquals(720, $lineHeight);
- $this->assertEquals('auto', $lineRule);
- }
-
- /**
- * Test setLineHeight validation
- */
- public function testLineHeightValidation()
- {
- $object = new Paragraph();
- $object->setLineHeight('12.5pt');
- $this->assertEquals(12.5, $object->getLineHeight());
- }
-
- /**
- * Test line height exception by using nonnumeric value
- *
- * @expectedException \PhpOffice\PhpWord\Exception\InvalidStyleException
- */
- public function testLineHeightException()
- {
- $object = new Paragraph();
- $object->setLineHeight('a');
- }
-}
diff --git a/tests/PhpWord/Style/SectionTest.php b/tests/PhpWord/Style/SectionTest.php
deleted file mode 100644
index 59d18167cb..0000000000
--- a/tests/PhpWord/Style/SectionTest.php
+++ /dev/null
@@ -1,347 +0,0 @@
-assertEquals('portrait', $oSettings->getOrientation());
- $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(), '', 0.000000001);
- $this->assertEquals(Section::DEFAULT_WIDTH, $oSettings->getPageSizeH(), '', 0.000000001);
-
- $iVal = rand(1, 1000);
- $oSettings->setSettingValue('borderSize', $iVal);
- $this->assertEquals(array($iVal, $iVal, $iVal, $iVal), $oSettings->getBorderSize());
- $this->assertEquals($iVal, $oSettings->getBorderBottomSize());
- $this->assertEquals($iVal, $oSettings->getBorderLeftSize());
- $this->assertEquals($iVal, $oSettings->getBorderRightSize());
- $this->assertEquals($iVal, $oSettings->getBorderTopSize());
-
- $oSettings->setSettingValue('borderColor', 'FF00AA');
- $this->assertEquals(array('FF00AA', 'FF00AA', 'FF00AA', 'FF00AA'), $oSettings->getBorderColor());
- $this->assertEquals('FF00AA', $oSettings->getBorderBottomColor());
- $this->assertEquals('FF00AA', $oSettings->getBorderLeftColor());
- $this->assertEquals('FF00AA', $oSettings->getBorderRightColor());
- $this->assertEquals('FF00AA', $oSettings->getBorderTopColor());
-
- $iVal = rand(1, 1000);
- $oSettings->setSettingValue('headerHeight', $iVal);
- $this->assertEquals($iVal, $oSettings->getHeaderHeight());
-
- $oSettings->setSettingValue('lineNumbering', array());
- $oSettings->setSettingValue(
- 'lineNumbering',
- array(
- 'start' => 1,
- 'increment' => 1,
- 'distance' => 240,
- 'restart' => 'newPage',
- )
- );
- $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\LineNumbering', $oSettings->getLineNumbering());
-
- $oSettings->setSettingValue('lineNumbering', null);
- $this->assertNull($oSettings->getLineNumbering());
- }
-
- /**
- * Set/get margin
- */
- public function testMargin()
- {
- // Section Settings
- $oSettings = new Section();
-
- $iVal = rand(1, 1000);
- $oSettings->setMarginTop($iVal);
- $this->assertEquals($iVal, $oSettings->getMarginTop());
-
- $iVal = rand(1, 1000);
- $oSettings->setMarginBottom($iVal);
- $this->assertEquals($iVal, $oSettings->getMarginBottom());
-
- $iVal = rand(1, 1000);
- $oSettings->setMarginLeft($iVal);
- $this->assertEquals($iVal, $oSettings->getMarginLeft());
-
- $iVal = rand(1, 1000);
- $oSettings->setMarginRight($iVal);
- $this->assertEquals($iVal, $oSettings->getMarginRight());
- }
-
- /**
- * Set/get page width
- */
- public function testPageWidth()
- {
- // Section Settings
- $oSettings = new Section();
-
- $this->assertEquals(Section::DEFAULT_WIDTH, $oSettings->getPageSizeW(), '', 0.000000001);
- $iVal = rand(1, 1000);
- $oSettings->setSettingValue('pageSizeW', $iVal);
- $this->assertEquals($iVal, $oSettings->getPageSizeW());
- }
-
- /**
- * Set/get page height
- */
- public function testPageHeight()
- {
- // Section Settings
- $oSettings = new Section();
-
- $this->assertEquals(Section::DEFAULT_HEIGHT, $oSettings->getPageSizeH(), '', 0.000000001);
- $iVal = rand(1, 1000);
- $oSettings->setSettingValue('pageSizeH', $iVal);
- $this->assertEquals($iVal, $oSettings->getPageSizeH());
- }
-
- /**
- * Set/get landscape orientation
- */
- public function testOrientationLandscape()
- {
- // Section Settings
- $oSettings = new Section();
-
- $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);
- }
-
- /**
- * Set/get portrait orientation
- */
- public function testOrientationPortrait()
- {
- // Section Settings
- $oSettings = new Section();
-
- $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);
- }
-
- /**
- * Set/get border size
- */
- public function testBorderSize()
- {
- // Section Settings
- $oSettings = new Section();
-
- $iVal = rand(1, 1000);
- $oSettings->setBorderSize($iVal);
- $this->assertEquals(array($iVal, $iVal, $iVal, $iVal), $oSettings->getBorderSize());
- $this->assertEquals($iVal, $oSettings->getBorderBottomSize());
- $this->assertEquals($iVal, $oSettings->getBorderLeftSize());
- $this->assertEquals($iVal, $oSettings->getBorderRightSize());
- $this->assertEquals($iVal, $oSettings->getBorderTopSize());
-
- $iVal = rand(1, 1000);
- $oSettings->setBorderBottomSize($iVal);
- $this->assertEquals($iVal, $oSettings->getBorderBottomSize());
-
- $iVal = rand(1, 1000);
- $oSettings->setBorderLeftSize($iVal);
- $this->assertEquals($iVal, $oSettings->getBorderLeftSize());
-
- $iVal = rand(1, 1000);
- $oSettings->setBorderRightSize($iVal);
- $this->assertEquals($iVal, $oSettings->getBorderRightSize());
-
- $iVal = rand(1, 1000);
- $oSettings->setBorderTopSize($iVal);
- $this->assertEquals($iVal, $oSettings->getBorderTopSize());
- }
-
- /**
- * Set/get border color
- */
- public function testBorderColor()
- {
- // Section Settings
- $oSettings = new Section();
-
- $oSettings->setBorderColor('FF00AA');
- $this->assertEquals(array('FF00AA', 'FF00AA', 'FF00AA', 'FF00AA'), $oSettings->getBorderColor());
- $this->assertEquals('FF00AA', $oSettings->getBorderBottomColor());
- $this->assertEquals('FF00AA', $oSettings->getBorderLeftColor());
- $this->assertEquals('FF00AA', $oSettings->getBorderRightColor());
- $this->assertEquals('FF00AA', $oSettings->getBorderTopColor());
-
- $oSettings->setBorderBottomColor('BBCCDD');
- $this->assertEquals('BBCCDD', $oSettings->getBorderBottomColor());
-
- $oSettings->setBorderLeftColor('CCDDEE');
- $this->assertEquals('CCDDEE', $oSettings->getBorderLeftColor());
-
- $oSettings->setBorderRightColor('11EE22');
- $this->assertEquals('11EE22', $oSettings->getBorderRightColor());
-
- $oSettings->setBorderTopColor('22FF33');
- $this->assertEquals('22FF33', $oSettings->getBorderTopColor());
- }
-
- /**
- * Set/get page numbering start
- */
- public function testNumberingStart()
- {
- // Section Settings
- $oSettings = new Section();
-
- $this->assertNull($oSettings->getPageNumberingStart());
-
- $iVal = rand(1, 1000);
- $oSettings->setPageNumberingStart($iVal);
- $this->assertEquals($iVal, $oSettings->getPageNumberingStart());
-
- $oSettings->setPageNumberingStart();
- $this->assertNull($oSettings->getPageNumberingStart());
- }
-
- /**
- * Set/get header height
- */
- public function testHeader()
- {
- $oSettings = new Section();
-
- $this->assertEquals(720, $oSettings->getHeaderHeight());
-
- $iVal = rand(1, 1000);
- $oSettings->setHeaderHeight($iVal);
- $this->assertEquals($iVal, $oSettings->getHeaderHeight());
-
- $oSettings->setHeaderHeight();
- $this->assertEquals(720, $oSettings->getHeaderHeight());
- }
-
- /**
- * Set/get footer height
- */
- public function testFooter()
- {
- // Section Settings
- $oSettings = new Section();
-
- $this->assertEquals(720, $oSettings->getFooterHeight());
-
- $iVal = rand(1, 1000);
- $oSettings->setFooterHeight($iVal);
- $this->assertEquals($iVal, $oSettings->getFooterHeight());
-
- $oSettings->setFooterHeight();
- $this->assertEquals(720, $oSettings->getFooterHeight());
- }
-
- /**
- * Set/get column number
- */
- public function testColumnsNum()
- {
- // Section Settings
- $oSettings = new Section();
-
- // Default
- $this->assertEquals(1, $oSettings->getColsNum());
-
- // Null value
- $oSettings->setColsNum();
- $this->assertEquals(1, $oSettings->getColsNum());
-
- // Random value
- $iVal = rand(1, 1000);
- $oSettings->setColsNum($iVal);
- $this->assertEquals($iVal, $oSettings->getColsNum());
- }
-
- /**
- * Set/get column spacing
- */
- public function testColumnsSpace()
- {
- // Section Settings
- $oSettings = new Section();
-
- // Default
- $this->assertEquals(720, $oSettings->getColsSpace());
-
- $iVal = rand(1, 1000);
- $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Section', $oSettings->setColsSpace($iVal));
- $this->assertEquals($iVal, $oSettings->getColsSpace());
-
- $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Section', $oSettings->setColsSpace());
- $this->assertEquals(720, $oSettings->getColsSpace());
- }
-
- /**
- * Set/get break type
- */
- public function testBreakType()
- {
- // Section Settings
- $oSettings = new Section();
-
- $this->assertNull($oSettings->getBreakType());
-
- $oSettings->setBreakType('continuous');
- $this->assertEquals('continuous', $oSettings->getBreakType());
-
- $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());
- }
-}
diff --git a/tests/PhpWord/Style/SpacingTest.php b/tests/PhpWord/Style/SpacingTest.php
deleted file mode 100644
index f7402edd12..0000000000
--- a/tests/PhpWord/Style/SpacingTest.php
+++ /dev/null
@@ -1,51 +0,0 @@
- array(null, 10),
- 'after' => array(null, 10),
- 'line' => array(null, 10),
- 'lineRule' => array('auto', 'exact'),
- );
- 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
- }
- }
-}
diff --git a/tests/PhpWord/Style/TOCTest.php b/tests/PhpWord/Style/TOCTest.php
deleted file mode 100644
index 445c5e4315..0000000000
--- a/tests/PhpWord/Style/TOCTest.php
+++ /dev/null
@@ -1,50 +0,0 @@
- array(TOC::TAB_LEADER_DOT, TOC::TAB_LEADER_UNDERSCORE),
- 'tabPos' => array(9062, 10),
- 'indent' => array(200, 10),
- );
- 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
- }
- }
-}
diff --git a/tests/PhpWord/Style/TabTest.php b/tests/PhpWord/Style/TabTest.php
deleted file mode 100644
index 8d8d3f6cf0..0000000000
--- a/tests/PhpWord/Style/TabTest.php
+++ /dev/null
@@ -1,50 +0,0 @@
- array(Tab::TAB_STOP_CLEAR, Tab::TAB_STOP_RIGHT),
- 'leader' => array(Tab::TAB_LEADER_NONE, Tab::TAB_LEADER_DOT),
- 'position' => array(0, 10),
- );
- 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
- }
- }
-}
diff --git a/tests/PhpWord/Style/TablePositionTest.php b/tests/PhpWord/Style/TablePositionTest.php
deleted file mode 100644
index 1243c3d595..0000000000
--- a/tests/PhpWord/Style/TablePositionTest.php
+++ /dev/null
@@ -1,65 +0,0 @@
- 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
deleted file mode 100644
index 91fc35509c..0000000000
--- a/tests/PhpWord/Style/TableTest.php
+++ /dev/null
@@ -1,222 +0,0 @@
- 'FF0000');
- $styleFirstRow = array('borderBottomSize' => 3);
-
- $object = new Table($styleTable, $styleFirstRow);
- $this->assertEquals('FF0000', $object->getBgColor());
-
- $firstRow = $object->getFirstRow();
- $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Table', $firstRow);
- $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());
- $this->assertNull($object->getIndent());
- }
-
- /**
- * Test setting style with normal value
- */
- 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,
- 'borderInsideHColor' => 'FF0000',
- 'borderInsideVSize' => 4,
- 'borderInsideVColor' => 'FF0000',
- 'cellMarginTop' => 240,
- 'cellMarginLeft' => 240,
- 'cellMarginRight' => 240,
- 'cellMarginBottom' => 240,
- 'alignment' => JcTable::CENTER,
- 'width' => 100,
- 'unit' => 'pct',
- 'layout' => Table::LAYOUT_FIXED,
- );
- foreach ($attributes as $key => $value) {
- $set = "set{$key}";
- $get = "get{$key}";
- $object->$set($value);
- $this->assertEquals($value, $object->$get());
- }
- }
-
- /**
- * Test border color
- *
- * Set border color and test if each part has the same color
- * While looping, push values array to be asserted with getBorderColor
- */
- public function testBorderColor()
- {
- $object = new Table();
- $parts = array('Top', 'Left', 'Right', 'Bottom', 'InsideH', 'InsideV');
-
- $value = 'FF0000';
- $object->setBorderColor($value);
- $values = array();
- foreach ($parts as $part) {
- $get = "getBorder{$part}Color";
- $values[] = $value;
- $this->assertEquals($value, $object->$get());
- }
- $this->assertEquals($values, $object->getBorderColor());
- }
-
- /**
- * Test border size
- *
- * Set border size and test if each part has the same size
- * While looping, push values array to be asserted with getBorderSize
- * Value is in eights of a point, i.e. 4 / 8 = .5pt
- */
- public function testBorderSize()
- {
- $object = new Table();
- $parts = array('Top', 'Left', 'Right', 'Bottom', 'InsideH', 'InsideV');
-
- $value = 4;
- $object->setBorderSize($value);
- $values = array();
- foreach ($parts as $part) {
- $get = "getBorder{$part}Size";
- $values[] = $value;
- $this->assertEquals($value, $object->$get());
- }
- $this->assertEquals($values, $object->getBorderSize());
- }
-
- /**
- * Test cell margin
- *
- * Set cell margin and test if each part has the same margin
- * While looping, push values array to be asserted with getCellMargin
- * Value is in twips
- */
- public function testCellMargin()
- {
- $object = new Table();
- $parts = array('Top', 'Left', 'Right', 'Bottom');
-
- $value = 240;
- $object->setCellMargin($value);
- $values = array();
- foreach ($parts as $part) {
- $get = "getCellMargin{$part}";
- $values[] = $value;
- $this->assertEquals($value, $object->$get());
- }
- $this->assertEquals($values, $object->getCellMargin());
- $this->assertTrue($object->hasMargin());
- }
-
- /**
- * Set style value for various special value types
- */
- public function testSetStyleValue()
- {
- $object = new Table();
- $object->setStyleValue('borderSize', 120);
- $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('999999', '999999', '999999', '999999', '999999', '999999'),
- $object->getBorderColor()
- );
- }
-
- /**
- * Tests table cell spacing
- */
- public function testTableCellSpacing()
- {
- $object = new Table();
- $this->assertNull($object->getCellSpacing());
-
- $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());
- }
-
- 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/Style/TextBoxTest.php b/tests/PhpWord/Style/TextBoxTest.php
deleted file mode 100644
index 803189cd19..0000000000
--- a/tests/PhpWord/Style/TextBoxTest.php
+++ /dev/null
@@ -1,306 +0,0 @@
- 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',
- );
- foreach ($properties as $key => $value) {
- $set = "set{$key}";
- $get = "get{$key}";
- $object->$set($value);
- $this->assertEquals($value, $object->$get());
- }
- }
-
- /**
- * Test setStyleValue method
- */
- public function testSetStyleValue()
- {
- $object = new TextBox();
-
- $properties = array(
- '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',
- );
- foreach ($properties as $key => $value) {
- $get = "get{$key}";
- $object->setStyleValue("{$key}", $value);
- $this->assertEquals($value, $object->$get());
- }
- }
-
- /**
- * Test setWrappingStyle exception
- *
- * @expectedException \InvalidArgumentException
- */
- public function testSetWrappingStyleException()
- {
- $object = new TextBox();
- $object->setWrappingStyle('foo');
- }
-
- /**
- * Test set/get width
- */
- public function testSetGetWidth()
- {
- $expected = 200;
- $object = new TextBox();
- $object->setWidth($expected);
- $this->assertEquals($expected, $object->getWidth());
- }
-
- /**
- * Test set/get height
- */
- public function testSetGetHeight()
- {
- $expected = 200;
- $object = new TextBox();
- $object->setHeight($expected);
- $this->assertEquals($expected, $object->getHeight());
- }
-
- /**
- * Test set/get height
- */
- public function testSetGetAlign()
- {
- $textBox = new TextBox();
-
- $expectedAlignment = Jc::START;
- $textBox->setAlignment($expectedAlignment);
- $this->assertEquals($expectedAlignment, $textBox->getAlignment());
- }
-
- /**
- * Test set/get marginTop
- */
- public function testSetGetMarginTop()
- {
- $expected = 5;
- $object = new TextBox();
- $object->setMarginTop($expected);
- $this->assertEquals($expected, $object->getMarginTop());
- }
-
- /**
- * Test set/get marginLeft
- */
- public function testSetGetMarginLeft()
- {
- $expected = 5;
- $object = new TextBox();
- $object->setMarginLeft($expected);
- $this->assertEquals($expected, $object->getMarginLeft());
- }
-
- /**
- * Test set/get innerMarginTop
- */
- public function testSetGetInnerMarginTop()
- {
- $expected = 5;
- $object = new TextBox();
- $object->setInnerMarginTop($expected);
- $this->assertEquals($expected, $object->getInnerMarginTop());
- }
-
- /**
- * Test set/get wrappingStyle
- */
- public function testSetGetWrappingStyle()
- {
- $expected = 'inline';
- $object = new TextBox();
- $object->setWrappingStyle($expected);
- $this->assertEquals($expected, $object->getWrappingStyle());
- }
-
- /**
- * Test set/get positioning
- */
- public function testSetGetPositioning()
- {
- $expected = 'absolute';
- $object = new TextBox();
- $object->setPositioning($expected);
- $this->assertEquals($expected, $object->getPositioning());
- }
-
- /**
- * Test set/get posHorizontal
- */
- public function testSetGetPosHorizontal()
- {
- $expected = 'center';
- $object = new TextBox();
- $object->setPosHorizontal($expected);
- $this->assertEquals($expected, $object->getPosHorizontal());
- }
-
- /**
- * Test set/get posVertical
- */
- public function testSetGetPosVertical()
- {
- $expected = 'top';
- $object = new TextBox();
- $object->setPosVertical($expected);
- $this->assertEquals($expected, $object->getPosVertical());
- }
-
- /**
- * Test set/get posHorizontalRel
- */
- public function testSetGetPosHorizontalRel()
- {
- $expected = 'margin';
- $object = new TextBox();
- $object->setPosHorizontalRel($expected);
- $this->assertEquals($expected, $object->getPosHorizontalRel());
- }
-
- /**
- * Test set/get posVerticalRel
- */
- public function testSetGetPosVerticalRel()
- {
- $expected = 'page';
- $object = new TextBox();
- $object->setPosVerticalRel($expected);
- $this->assertEquals($expected, $object->getPosVerticalRel());
- }
-
- /**
- * Test set/get innerMarginRight
- */
- public function testSetGetInnerMarginRight()
- {
- $expected = 5;
- $object = new TextBox();
- $object->setInnerMarginRight($expected);
- $this->assertEquals($expected, $object->getInnerMarginRight());
- }
-
- /**
- * Test set/get innerMarginBottom
- */
- public function testSetGetInnerMarginBottom()
- {
- $expected = 5;
- $object = new TextBox();
- $object->setInnerMarginBottom($expected);
- $this->assertEquals($expected, $object->getInnerMarginBottom());
- }
-
- /**
- * Test set/get innerMarginLeft
- */
- public function testSetGetInnerMarginLeft()
- {
- $expected = 5;
- $object = new TextBox();
- $object->setInnerMarginLeft($expected);
- $this->assertEquals($expected, $object->getInnerMarginLeft());
- }
-
- /**
- * Test set/get innerMarginLeft
- */
- public function testSetGetInnerMargin()
- {
- $expected = 5;
- $object = new TextBox();
- $object->setInnerMargin($expected);
- $this->assertEquals(array($expected, $expected, $expected, $expected), $object->getInnerMargin());
- }
-
- /**
- * Test set/get borderSize
- */
- public function testSetGetBorderSize()
- {
- $expected = 2;
- $object = new TextBox();
- $object->setBorderSize($expected);
- $this->assertEquals($expected, $object->getBorderSize());
- }
-
- /**
- * Test set/get borderColor
- */
- public function testSetGetBorderColor()
- {
- $expected = 'red';
- $object = new TextBox();
- $object->setBorderColor($expected);
- $this->assertEquals($expected, $object->getBorderColor());
- }
-}
diff --git a/tests/PhpWord/TemplateProcessorTest.php b/tests/PhpWord/TemplateProcessorTest.php
deleted file mode 100644
index 4caca77aeb..0000000000
--- a/tests/PhpWord/TemplateProcessorTest.php
+++ /dev/null
@@ -1,847 +0,0 @@
-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()
- {
- $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.', '${reference.') as $needle) {
- $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.');
- $this->assertFileExists($documentFqfn, "The saved document \"{$documentFqfn}\" doesn't exist.");
-
- $templateZip = new \ZipArchive();
- $templateZip->open($templateFqfn);
- $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);
- $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}\".");
- }
-
- $this->assertNotEquals($templateHeaderXml, $documentHeaderXml);
- $this->assertNotEquals($templateMainPartXml, $documentMainPartXml);
- $this->assertNotEquals($templateFooterXml, $documentFooterXml);
- $this->assertEquals($embeddingText, $documentEmbedding);
-
- return $documentFqfn;
- }
-
- /**
- * XSL stylesheet can be applied.
- *
- * @test
- * @covers ::applyXslStyleSheet
- * @depends testTemplateCanBeSavedInTemporaryLocation
- *
- * @param string $actualDocumentFqfn
- *
- * @throws \Exception
- */
- final public function testXslStyleSheetCanBeApplied($actualDocumentFqfn)
- {
- $expectedDocumentFqfn = __DIR__ . '/_files/documents/without_table_macros.docx';
-
- $actualDocumentZip = new \ZipArchive();
- $actualDocumentZip->open($actualDocumentFqfn);
- $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);
- $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($expectedHeaderXml, $actualHeaderXml);
- $this->assertXmlStringEqualsXmlString($expectedMainPartXml, $actualMainPartXml);
- $this->assertXmlStringEqualsXmlString($expectedFooterXml, $actualFooterXml);
- }
-
- /**
- * 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()
- {
- $templateProcessor = new TemplateProcessor(__DIR__ . '/_files/templates/blank.docx');
-
- $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'));
- }
-
- /**
- * 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()
- {
- $templateProcessor = new TemplateProcessor(__DIR__ . '/_files/templates/corrupted_main_document_part.docx');
-
- $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);
- }
-
- /**
- * @covers ::setValue
- * @covers ::cloneRow
- * @covers ::saveAs
- * @test
- */
- public function testCloneRow()
- {
- $templateProcessor = new TemplateProcessor(__DIR__ . '/_files/templates/clone-merge.docx');
-
- $this->assertEquals(
- array('tableHeader', 'userId', 'userName', 'userLocation'),
- $templateProcessor->getVariables()
- );
-
- $docName = 'clone-test-result.docx';
- $templateProcessor->setValue('tableHeader', utf8_decode('ééé'));
- $templateProcessor->cloneRow('userId', 1);
- $templateProcessor->setValue('userId#1', 'Test');
- $templateProcessor->saveAs($docName);
- $docFound = file_exists($docName);
- unlink($docName);
- $this->assertTrue($docFound);
- }
-
- /**
- * @covers ::setValue
- * @covers ::cloneRow
- * @covers ::saveAs
- * @test
- */
- public function testCloneRowAndSetValues()
- {
- $mainPart = '
-
-
-
-
-
-
-
- ${userId}
-
-
-
-
-
-
- ${userName}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- ${userLocation}
-
-
-
-
- ';
- $templateProcessor = new TestableTemplateProcesor($mainPart);
-
- $this->assertEquals(
- array('userId', 'userName', 'userLocation'),
- $templateProcessor->getVariables()
- );
-
- $values = array(
- array('userId' => 1, 'userName' => 'Batman', 'userLocation' => 'Gotham City'),
- array('userId' => 2, 'userName' => 'Superman', 'userLocation' => 'Metropolis'),
- );
- $templateProcessor->setValue('tableHeader', 'My clonable table');
- $templateProcessor->cloneRowAndSetValues('userId', $values);
- $this->assertContains('Superman ', $templateProcessor->getMainPart());
- $this->assertContains('Metropolis ', $templateProcessor->getMainPart());
- }
-
- /**
- * @expectedException \Exception
- * @test
- */
- public function testCloneNotExistingRowShouldThrowException()
- {
- $mainPart = 'text ';
- $templateProcessor = new TestableTemplateProcesor($mainPart);
-
- $templateProcessor->cloneRow('fake_search', 2);
- }
-
- /**
- * @covers ::setValue
- * @covers ::saveAs
- * @test
- */
- public function testMacrosCanBeReplacedInHeaderAndFooter()
- {
- $templateProcessor = new TemplateProcessor(__DIR__ . '/_files/templates/header-footer.docx');
-
- $this->assertEquals(array('documentContent', 'headerValue:100:100', 'footerValue'), $templateProcessor->getVariables());
-
- $macroNames = array('headerValue', 'documentContent', 'footerValue');
- $macroValues = array('Header Value', 'Document text.', 'Footer Value');
- $templateProcessor->setValue($macroNames, $macroValues);
-
- $docName = 'header-footer-test-result.docx';
- $templateProcessor->saveAs($docName);
- $docFound = file_exists($docName);
- unlink($docName);
- $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()
- );
- }
-
- 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
- */
- public function testSetValues()
- {
- $mainPart = '
-
-
- Hello ${firstname} ${lastname}
-
- ';
-
- $templateProcessor = new TestableTemplateProcesor($mainPart);
- $templateProcessor->setValues(array('firstname' => 'John', 'lastname' => 'Doe'));
-
- $this->assertContains('Hello John Doe', $templateProcessor->getMainPart());
- }
-
- /**
- * @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
- * @covers ::saveAs
- * @test
- */
- public function testCloneDeleteBlock()
- {
- $templateProcessor = new TemplateProcessor(__DIR__ . '/_files/templates/clone-delete-block.docx');
-
- $this->assertEquals(
- 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);
- $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);
-
- $templateProcessor = new TemplateProcessor($templatePath);
- $variableCount = $templateProcessor->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
- );
- }
-
- /**
- * @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();
- /** @var \PhpOffice\PhpWord\Element\TextRun[] $actualElements */
- $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]->getElement(0)->getText()
- );
- }
- }
-
- /**
- * @covers ::cloneBlock
- * @test
- */
- public function testCloneBlock()
- {
- $mainPart = '
-
-
-
- ${CLONEME}
-
-
-
-
- This block will be cloned with ${variable}
-
-
-
-
- ${/CLONEME}
-
- ';
-
- $templateProcessor = new TestableTemplateProcesor($mainPart);
- $templateProcessor->cloneBlock('CLONEME', 3);
-
- $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());
- }
-
- 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.
- *
- * @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);
- }
-
- /**
- * @covers ::getMainPartName
- */
- public function testMainPartNameDetection()
- {
- $templateProcessor = new TemplateProcessor(__DIR__ . '/_files/templates/document22-xml.docx');
-
- $variables = array('test');
-
- $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);
- }
-
- /**
- * @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']));
- }
-
- 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);
- }
-
- 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/Writer/HTML/ElementTest.php b/tests/PhpWord/Writer/HTML/ElementTest.php
deleted file mode 100644
index 101e226f50..0000000000
--- a/tests/PhpWord/Writer/HTML/ElementTest.php
+++ /dev/null
@@ -1,189 +0,0 @@
-assertEquals('', $object->write());
- }
- }
-
- /**
- * Test write element text
- */
- public function testWriteTextElement()
- {
- $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(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()));
-
- $dom = $this->getAsHTML($phpWord);
- $xpath = new \DOMXPath($dom);
-
- $this->assertEquals(1, $xpath->query('/html/body/p[1]/ins')->length);
- $this->assertEquals(1, $xpath->query('/html/body/p[2]/del')->length);
- }
-
- /**
- * 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, 'bgColor' => '6086B8'));
- $cell11->addText('cell spanning 2 bellow');
- $row2 = $table->addRow();
- $cell21 = $row2->addCell(500, array('bgColor' => 'ffffff'));
- $cell21->addText('first cell');
- $cell22 = $row2->addCell(500);
- $cell22->addText('second cell');
-
- $dom = $this->getAsHTML($phpWord);
- $xpath = new \DOMXPath($dom);
-
- $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->assertEquals(2, $xpath->query('/html/body/table/tr[2]/td')->length);
-
- $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'));
- }
-
- /**
- * 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);
- $xpath = new \DOMXPath($dom);
-
- $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->assertEquals(1, $xpath->query('/html/body/table/tr[2]/td')->length);
- }
-
- private function getAsHTML(PhpWord $phpWord)
- {
- $htmlWriter = new HTML($phpWord);
- $dom = new \DOMDocument();
- $dom->loadHTML($htmlWriter->getContent());
-
- 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->assertContains($expected, $content);
- }
-
- /**
- * Tests writing table with layout
- */
- public function testWriteTableLayout()
- {
- $phpWord = new PhpWord();
- $section = $phpWord->addSection();
- $section->addTable();
-
- $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[1]')->item(0)->attributes->getNamedItem('style')->textContent);
- $this->assertEquals('table-layout: auto;', $xpath->query('/html/body/table[2]')->item(0)->attributes->getNamedItem('style')->textContent);
- }
-}
diff --git a/tests/PhpWord/Writer/ODText/ElementTest.php b/tests/PhpWord/Writer/ODText/ElementTest.php
deleted file mode 100644
index 37f0d1ef52..0000000000
--- a/tests/PhpWord/Writer/ODText/ElementTest.php
+++ /dev/null
@@ -1,62 +0,0 @@
-write();
-
- $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'));
- }
-}
diff --git a/tests/PhpWord/Writer/ODText/Part/AbstractPartTest.php b/tests/PhpWord/Writer/ODText/Part/AbstractPartTest.php
deleted file mode 100644
index 51d893d23e..0000000000
--- a/tests/PhpWord/Writer/ODText/Part/AbstractPartTest.php
+++ /dev/null
@@ -1,52 +0,0 @@
-getMockForAbstractClass('PhpOffice\\PhpWord\\Writer\\ODText\\Part\\AbstractPart');
- $object->setParentWriter(new ODText());
- $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->getParentWriter();
- }
-}
diff --git a/tests/PhpWord/Writer/PDF/MPDFTest.php b/tests/PhpWord/Writer/PDF/MPDFTest.php
deleted file mode 100644
index 34a5f8d86b..0000000000
--- a/tests/PhpWord/Writer/PDF/MPDFTest.php
+++ /dev/null
@@ -1,53 +0,0 @@
-addSection();
- $section->addText('Test 1');
- $section->addPageBreak();
-
- $rendererName = Settings::PDF_RENDERER_MPDF;
- $rendererLibraryPath = realpath(PHPWORD_TESTS_BASE_DIR . '/../vendor/mpdf/mpdf');
- Settings::setPdfRenderer($rendererName, $rendererLibraryPath);
- $writer = new PDF($phpWord);
- $writer->save($file);
-
- $this->assertFileExists($file);
-
- unlink($file);
- }
-}
diff --git a/tests/PhpWord/Writer/RTF/ElementTest.php b/tests/PhpWord/Writer/RTF/ElementTest.php
deleted file mode 100644
index 47630335a3..0000000000
--- a/tests/PhpWord/Writer/RTF/ElementTest.php
+++ /dev/null
@@ -1,42 +0,0 @@
-assertEquals('', $object->write());
- }
- }
-}
diff --git a/tests/PhpWord/Writer/RTF/StyleTest.php b/tests/PhpWord/Writer/RTF/StyleTest.php
deleted file mode 100644
index 317014c610..0000000000
--- a/tests/PhpWord/Writer/RTF/StyleTest.php
+++ /dev/null
@@ -1,111 +0,0 @@
-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);
- }
-
- 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);
- }
-}
diff --git a/tests/PhpWord/Writer/Word2007/ElementTest.php b/tests/PhpWord/Writer/Word2007/ElementTest.php
deleted file mode 100644
index 703f4590e8..0000000000
--- a/tests/PhpWord/Writer/Word2007/ElementTest.php
+++ /dev/null
@@ -1,513 +0,0 @@
-write();
-
- $this->assertEquals('', $xmlWriter->getData());
- }
- }
-
- /**
- * Test line element
- */
- public function testLineElement()
- {
- $phpWord = new PhpWord();
- $section = $phpWord->addSection();
-
- $section->addLine(array('width' => 1000, 'height' => 1000, 'positioning' => 'absolute', 'flip' => true));
- $doc = TestHelperDOCX::getDocument($phpWord);
-
- $element = '/w:document/w:body/w:p/w:r/w:pict/v:shapetype';
- $this->assertTrue($doc->elementExists($element));
- }
-
- /**
- * 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'));
- }
-
- /**
- * 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
- */
- public function testShapeElements()
- {
- $phpWord = new PhpWord();
- $section = $phpWord->addSection();
-
- // Arc
- $section->addShape(
- 'arc',
- array(
- 'points' => '-90 20',
- 'frame' => array('width' => 120, 'height' => 120),
- 'outline' => array('color' => '#333333', 'weight' => 2, 'startArrow' => 'oval', 'endArrow' => 'open'),
- )
- );
-
- // Curve
- $section->addShape(
- 'curve',
- array(
- 'points' => '1,100 200,1 1,50 200,50', 'connector' => 'elbow',
- 'outline' => array(
- 'color' => '#66cc00',
- 'weight' => 2,
- 'dash' => 'dash',
- 'startArrow' => 'diamond',
- 'endArrow' => 'block',
- ),
- )
- );
-
- // Line
- $section->addShape(
- 'line',
- array(
- 'points' => '1,1 150,30',
- 'outline' => array(
- 'color' => '#cc00ff',
- 'line' => 'thickThin',
- 'weight' => 3,
- 'startArrow' => 'oval',
- 'endArrow' => 'classic',
- 'endCap' => 'round',
- ),
- )
- );
-
- // Polyline
- $section->addShape(
- 'polyline',
- array(
- 'points' => '1,30 20,10 55,20 75,10 100,40 115,50, 120,15 200,50',
- 'outline' => array(
- 'color' => '#cc6666',
- 'weight' => 2,
- 'startArrow' => 'none',
- 'endArrow' => 'classic',
- ),
- )
- );
-
- // Rectangle
- $section->addShape(
- 'rect',
- array(
- 'roundness' => 0.2,
- 'frame' => array('width' => 100, 'height' => 100, 'left' => 1, 'top' => 1),
- 'fill' => array('color' => '#FFCC33'),
- 'outline' => array('color' => '#990000', 'weight' => 1),
- 'shadow' => array('color' => '#EEEEEE', 'offset' => '3pt,3pt'),
- )
- );
-
- // Oval
- $section->addShape(
- 'oval',
- array(
- 'frame' => array('width' => 100, 'height' => 70, 'left' => 1, 'top' => 1),
- 'fill' => array('color' => '#33CC99'),
- 'outline' => array('color' => '#333333', 'weight' => 2),
- 'extrusion' => array('type' => 'perspective', 'color' => '#EEEEEE'),
- )
- );
-
- $doc = TestHelperDOCX::getDocument($phpWord);
-
- $elements = array('arc', 'curve', 'line', 'polyline', 'roundrect', 'oval');
- foreach ($elements as $element) {
- $path = "/w:document/w:body/w:p/w:r/w:pict/v:{$element}";
- $this->assertTrue($doc->elementExists($path));
- }
- }
-
- /**
- * 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));
- }
- }
-
- 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'));
- $section->addField('STYLEREF', array('StyleIdentifier' => 'Heading 1'));
- $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 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
- */
- 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'));
- }
-
- /**
- * Test SDT elements
- */
- public function testSDTElements()
- {
- $phpWord = new PhpWord();
- $section = $phpWord->addSection();
-
- $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);
-
- $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'));
-
- $this->assertTrue($doc->elementExists($path . '[4]/w:sdt/w:sdtPr/w:text'));
- }
-
- /**
- * 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'));
- }
-
- /**
- * Test Track changes
- */
- 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'));
- }
-
- /**
- * 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'));
- }
-
- /**
- * 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);
- }
-}
diff --git a/tests/PhpWord/Writer/Word2007/Part/AbstractPartTest.php b/tests/PhpWord/Writer/Word2007/Part/AbstractPartTest.php
deleted file mode 100644
index fac94882d2..0000000000
--- a/tests/PhpWord/Writer/Word2007/Part/AbstractPartTest.php
+++ /dev/null
@@ -1,52 +0,0 @@
-getMockForAbstractClass('PhpOffice\\PhpWord\\Writer\\Word2007\\Part\\AbstractPart');
- $object->setParentWriter(new Word2007());
- $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->getParentWriter();
- }
-}
diff --git a/tests/PhpWord/Writer/Word2007/Style/FontTest.php b/tests/PhpWord/Writer/Word2007/Style/FontTest.php
deleted file mode 100644
index ccfffbfb01..0000000000
--- a/tests/PhpWord/Writer/Word2007/Style/FontTest.php
+++ /dev/null
@@ -1,83 +0,0 @@
-addSection();
- $textrun = $section->addTextRun();
- $textrun->addText('سلام این یک پاراگراف راست به چپ است', array('rtl' => true, 'lang' => 'ar-DZ'));
- $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007');
-
- $file = 'word/document.xml';
- $path = '/w:document/w:body/w:p/w:r/w:rPr/w:rtl';
- $this->assertTrue($doc->elementExists($path, $file));
- }
-
- /**
- * 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));
- }
-
- /**
- * 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'));
- }
-}
diff --git a/tests/PhpWord/Writer/Word2007/Style/ImageTest.php b/tests/PhpWord/Writer/Word2007/Style/ImageTest.php
deleted file mode 100644
index efa0a10534..0000000000
--- a/tests/PhpWord/Writer/Word2007/Style/ImageTest.php
+++ /dev/null
@@ -1,69 +0,0 @@
- 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);
- }
-}
diff --git a/tests/PhpWord/_includes/AbstractTestReader.php b/tests/PhpWord/_includes/AbstractTestReader.php
deleted file mode 100644
index d9097d717f..0000000000
--- a/tests/PhpWord/_includes/AbstractTestReader.php
+++ /dev/null
@@ -1,64 +0,0 @@
- 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(array $partXmls = array())
- {
- $file = __DIR__ . '/../_files/temp.docx';
- $zip = new \ZipArchive();
- $zip->open($file, \ZipArchive::CREATE);
- 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();
-
- $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;
- }
-}
diff --git a/tests/PhpWord/_includes/XmlDocument.php b/tests/PhpWord/_includes/XmlDocument.php
deleted file mode 100644
index 3a7869bcea..0000000000
--- a/tests/PhpWord/_includes/XmlDocument.php
+++ /dev/null
@@ -1,194 +0,0 @@
-path = realpath($path);
- }
-
- /**
- * Get DOM from file
- *
- * @param string $file
- * @return \DOMDocument
- */
- public function getFileDom($file = 'word/document.xml')
- {
- if (null !== $this->dom && $file === $this->file) {
- return $this->dom;
- }
-
- $this->xpath = null;
- $this->file = $file;
-
- $file = $this->path . '/' . $file;
- $orignalLibEntityLoader = libxml_disable_entity_loader(false);
- $this->dom = new \DOMDocument();
- $this->dom->load($file);
- libxml_disable_entity_loader($orignalLibEntityLoader);
-
- return $this->dom;
- }
-
- /**
- * Get node list
- *
- * @param string $path
- * @param string $file
- * @return \DOMNodeList
- */
- public function getNodeList($path, $file = 'word/document.xml')
- {
- if (null === $this->dom || $file !== $this->file) {
- $this->getFileDom($file);
- }
-
- 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);
- }
-
- /**
- * Get element
- *
- * @param string $path
- * @param string $file
- * @return \DOMElement
- */
- public function getElement($path, $file = 'word/document.xml')
- {
- $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()
- {
- return $this->path;
- }
-
- /**
- * Get element attribute
- *
- * @param string $path
- * @param string $attribute
- * @param string $file
- * @return string
- */
- public function getElementAttribute($path, $attribute, $file = 'word/document.xml')
- {
- return $this->getElement($path, $file)->getAttribute($attribute);
- }
-
- /**
- * Check if element exists
- *
- * @param string $path
- * @param string $file
- * @return string
- */
- public function elementExists($path, $file = 'word/document.xml')
- {
- $nodeList = $this->getNodeList($path, $file);
-
- 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 = '/', $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($element, true);
- $newdoc->appendChild($node);
-
- return $newdoc->saveXML($node);
- }
-}
diff --git a/tests/PhpWordTests/AbstractTestReader.php b/tests/PhpWordTests/AbstractTestReader.php
new file mode 100644
index 0000000000..a51af6b96a
--- /dev/null
+++ b/tests/PhpWordTests/AbstractTestReader.php
@@ -0,0 +1,66 @@
+ ['class' => 'PhpOffice\PhpWord\Reader\Word2007\Styles', 'xml' => ' {toReplace} '],
+ 'document' => ['class' => 'PhpOffice\PhpWord\Reader\Word2007\Document', 'xml' => '{toReplace} '],
+ 'footnotes' => ['class' => 'PhpOffice\PhpWord\Reader\Word2007\Footnotes', 'xml' => '{toReplace} '],
+ 'endnotes' => ['class' => 'PhpOffice\PhpWord\Reader\Word2007\Endnotes', 'xml' => '{toReplace} '],
+ 'settings' => ['class' => 'PhpOffice\PhpWord\Reader\Word2007\Settings', 'xml' => '{toReplace} '],
+ ];
+
+ /**
+ * Builds a PhpWord instance based on the xml passed.
+ *
+ * @return PhpWord
+ */
+ protected function getDocumentFromString(array $partXmls = [])
+ {
+ $file = __DIR__ . '/_files/temp.docx';
+ $zip = new ZipArchive();
+ $zip->open($file, ZipArchive::CREATE | ZipArchive::OVERWRITE);
+ 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();
+
+ $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;
+ }
+}
diff --git a/tests/PhpWord/_includes/AbstractWebServerEmbeddedTest.php b/tests/PhpWordTests/AbstractWebServerEmbedded.php
similarity index 68%
rename from tests/PhpWord/_includes/AbstractWebServerEmbeddedTest.php
rename to tests/PhpWordTests/AbstractWebServerEmbedded.php
index 9316a9fe61..fde7e1007c 100644
--- a/tests/PhpWord/_includes/AbstractWebServerEmbeddedTest.php
+++ b/tests/PhpWordTests/AbstractWebServerEmbedded.php
@@ -1,4 +1,5 @@
start();
- while (!self::$httpServer->isRunning()) {
- usleep(1000);
- }
+ $commandLine = 'php -S localhost:8080 -t tests/PhpWordTests/_files';
+
+ self::$httpServer = Process::fromShellCommandline($commandLine);
+ self::$httpServer->start();
+ while (!self::$httpServer->isRunning()) {
+ usleep(1000);
}
}
- public static function tearDownAfterClass()
+ public static function tearDownAfterClass(): void
{
- if (self::isBuiltinServerSupported()) {
- self::$httpServer->stop();
- }
+ self::$httpServer->stop();
}
protected static function getBaseUrl()
@@ -55,6 +54,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) {
@@ -72,9 +80,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', '>=');
- }
}
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 @@
+addItem(new Footnote()); // addItem #1
- $this->assertEquals(2, $object->addItem(new Footnote())); // addItem #2. Should returns new item index
- $this->assertCount(2, $object->getItems()); // getItems returns array
- $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Footnote', $object->getItem(1)); // getItem returns object
- $this->assertNull($object->getItem(3)); // getItem returns null when invalid index is referenced
+ self::assertEquals(1, $object->addItem(new Footnote())); // addItem #2. Should returns new item index
+ self::assertCount(2, $object->getItems()); // getItems returns array
+ 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
- $this->assertNull($object->getItem(2)); // Check if it's null
+ self::assertNull($object->getItem(2)); // Check if it's null
+ }
+
+ 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/PhpWord/ComplexType/FootnotePropertiesTest.php b/tests/PhpWordTests/ComplexType/FootnotePropertiesTest.php
similarity index 61%
rename from tests/PhpWord/ComplexType/FootnotePropertiesTest.php
rename to tests/PhpWordTests/ComplexType/FootnotePropertiesTest.php
index 4448daf865..6472968d3b 100644
--- a/tests/PhpWord/ComplexType/FootnotePropertiesTest.php
+++ b/tests/PhpWordTests/ComplexType/FootnotePropertiesTest.php
@@ -1,4 +1,5 @@
setPos(FootnoteProperties::POSITION_DOC_END);
@@ -38,41 +42,38 @@ public function testSetGetNormal()
$footnoteProp->setNumStart(2);
$footnoteProp->setNumRestart(FootnoteProperties::RESTART_NUMBER_EACH_PAGE);
- $this->assertEquals(FootnoteProperties::POSITION_DOC_END, $footnoteProp->getPos());
- $this->assertEquals(NumberFormat::LOWER_ROMAN, $footnoteProp->getNumFmt());
- $this->assertEquals(2, $footnoteProp->getNumStart());
- $this->assertEquals(FootnoteProperties::RESTART_NUMBER_EACH_PAGE, $footnoteProp->getNumRestart());
+ self::assertEquals(FootnoteProperties::POSITION_DOC_END, $footnoteProp->getPos());
+ self::assertEquals(NumberFormat::LOWER_ROMAN, $footnoteProp->getNumFmt());
+ self::assertEquals(2, $footnoteProp->getNumStart());
+ self::assertEquals(FootnoteProperties::RESTART_NUMBER_EACH_PAGE, $footnoteProp->getNumRestart());
}
/**
- * Test throws exception if wrong position given
- *
- * @expectedException \InvalidArgumentException
+ * Test throws exception if wrong position given.
*/
- public function testWrongPos()
+ public function testWrongPos(): void
{
+ $this->expectException(InvalidArgumentException::class);
$footnoteProp = new FootnoteProperties();
$footnoteProp->setPos(NumberFormat::LOWER_ROMAN);
}
/**
- * Test throws exception if wrong number format given
- *
- * @expectedException \InvalidArgumentException
+ * Test throws exception if wrong number format given.
*/
- public function testWrongNumFmt()
+ public function testWrongNumFmt(): void
{
+ $this->expectException(InvalidArgumentException::class);
$footnoteProp = new FootnoteProperties();
$footnoteProp->setNumFmt(FootnoteProperties::POSITION_DOC_END);
}
/**
- * Test throws exception if wrong number restart given
- *
- * @expectedException \InvalidArgumentException
+ * Test throws exception if wrong number restart given.
*/
- public function testWrongNumRestart()
+ public function testWrongNumRestart(): void
{
+ $this->expectException(InvalidArgumentException::class);
$footnoteProp = new FootnoteProperties();
$footnoteProp->setNumRestart(NumberFormat::LOWER_ROMAN);
}
diff --git a/tests/PhpWord/ComplexType/ProofStateTest.php b/tests/PhpWordTests/ComplexType/ProofStateTest.php
similarity index 66%
rename from tests/PhpWord/ComplexType/ProofStateTest.php
rename to tests/PhpWordTests/ComplexType/ProofStateTest.php
index cd1e77f7f0..700e3f6d98 100644
--- a/tests/PhpWord/ComplexType/ProofStateTest.php
+++ b/tests/PhpWordTests/ComplexType/ProofStateTest.php
@@ -1,4 +1,5 @@
setGrammar(ProofState::CLEAN);
$pState->setSpelling(ProofState::DIRTY);
- $this->assertEquals(ProofState::CLEAN, $pState->getGrammar());
- $this->assertEquals(ProofState::DIRTY, $pState->getSpelling());
+ self::assertEquals(ProofState::CLEAN, $pState->getGrammar());
+ self::assertEquals(ProofState::DIRTY, $pState->getSpelling());
}
/**
- * Test throws exception if wrong grammar proof state value given
- *
- * @expectedException \InvalidArgumentException
+ * Test throws exception if wrong grammar proof state value given.
*/
- public function testWrongGrammar()
+ public function testWrongGrammar(): void
{
+ $this->expectException(InvalidArgumentException::class);
$pState = new ProofState();
$pState->setGrammar('Wrong');
}
/**
- * Test throws exception if wrong spelling proof state value given
- *
- * @expectedException \InvalidArgumentException
+ * Test throws exception if wrong spelling proof state value given.
*/
- public function testWrongSpelling()
+ public function testWrongSpelling(): void
{
+ $this->expectException(InvalidArgumentException::class);
$pState = new ProofState();
$pState->setSpelling('Wrong');
}
diff --git a/tests/PhpWordTests/ComplexType/RubyPropertiesTest.php b/tests/PhpWordTests/ComplexType/RubyPropertiesTest.php
new file mode 100644
index 0000000000..62bc0b0739
--- /dev/null
+++ b/tests/PhpWordTests/ComplexType/RubyPropertiesTest.php
@@ -0,0 +1,140 @@
+getAlignment());
+ self::assertNotEmpty($properties->getAlignment());
+ self::assertIsFloat($properties->getFontFaceSize());
+ self::assertIsFloat($properties->getFontPointsAboveBaseText());
+ self::assertIsFloat($properties->getFontSizeForBaseText());
+ self::assertIsString($properties->getLanguageId());
+ self::assertTrue($properties->getLanguageId() !== '');
+ }
+
+ /**
+ * Get/set alignment.
+ */
+ public function testAlignment(): void
+ {
+ $properties = new RubyProperties();
+ self::assertIsString($properties->getAlignment());
+ self::assertNotEmpty($properties->getAlignment());
+ $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::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
new file mode 100644
index 0000000000..9ce05750b8
--- /dev/null
+++ b/tests/PhpWordTests/Element/AbstractElementTest.php
@@ -0,0 +1,62 @@
+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());
+ }
+
+ /**
+ * Test set/get element unique Id.
+ */
+ public function testElementId(): void
+ {
+ // @phpstan-ignore-next-line
+ 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/PhpWord/Element/BookmarkTest.php b/tests/PhpWordTests/Element/BookmarkTest.php
similarity index 71%
rename from tests/PhpWord/Element/BookmarkTest.php
rename to tests/PhpWordTests/Element/BookmarkTest.php
index 04e3f6d547..097166736f 100644
--- a/tests/PhpWord/Element/BookmarkTest.php
+++ b/tests/PhpWordTests/Element/BookmarkTest.php
@@ -1,4 +1,5 @@
assertInstanceOf('PhpOffice\\PhpWord\\Element\\Bookmark', $oBookmark);
- $this->assertEquals($bookmarkName, $oBookmark->getName());
+ self::assertEquals($bookmarkName, $oBookmark->getName());
}
}
diff --git a/tests/PhpWordTests/Element/CellTest.php b/tests/PhpWordTests/Element/CellTest.php
new file mode 100644
index 0000000000..2fedcafc24
--- /dev/null
+++ b/tests/PhpWordTests/Element/CellTest.php
@@ -0,0 +1,273 @@
+getWidth());
+ }
+
+ /**
+ * New instance with array.
+ */
+ public function testConstructWithStyleArray(): void
+ {
+ $oCell = new Cell(null, ['valign' => 'center']);
+
+ self::assertInstanceOf('PhpOffice\\PhpWord\\Style\\Cell', $oCell->getStyle());
+ self::assertNull($oCell->getWidth());
+ }
+
+ /**
+ * Add text.
+ */
+ public function testAddText(): void
+ {
+ $oCell = new Cell();
+ $element = $oCell->addText('text');
+
+ self::assertCount(1, $oCell->getElements());
+ self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\Text', $element);
+ }
+
+ /**
+ * Add non-UTF8.
+ */
+ public function testAddTextNotUTF8(): void
+ {
+ $oCell = new Cell();
+ $element = $oCell->addText(utf8decode('ééé'));
+
+ self::assertCount(1, $oCell->getElements());
+ self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\Text', $element);
+ self::assertEquals('ééé', $element->getText());
+ }
+
+ /**
+ * Add link.
+ */
+ public function testAddLink(): void
+ {
+ $oCell = new Cell();
+ $element = $oCell->addLink(utf8decode('ééé'), utf8decode('ééé'));
+
+ self::assertCount(1, $oCell->getElements());
+ self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\Link', $element);
+ }
+
+ /**
+ * Add text break.
+ */
+ public function testAddTextBreak(): void
+ {
+ $oCell = new Cell();
+ $oCell->addTextBreak();
+
+ self::assertCount(1, $oCell->getElements());
+ }
+
+ /**
+ * Add list item.
+ */
+ public function testAddListItem(): void
+ {
+ $oCell = new Cell();
+ $element = $oCell->addListItem('text');
+
+ self::assertCount(1, $oCell->getElements());
+ self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\ListItem', $element);
+ self::assertEquals('text', $element->getTextObject()->getText());
+ }
+
+ /**
+ * Add list item non-UTF8.
+ */
+ public function testAddListItemNotUTF8(): void
+ {
+ $oCell = new Cell();
+ $element = $oCell->addListItem(utf8decode('ééé'));
+
+ self::assertCount(1, $oCell->getElements());
+ self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\ListItem', $element);
+ self::assertEquals('ééé', $element->getTextObject()->getText());
+ }
+
+ /**
+ * Add image section.
+ */
+ public function testAddImageSection(): void
+ {
+ $src = __DIR__ . '/../_files/images/earth.jpg';
+ $oCell = new Cell();
+ $element = $oCell->addImage($src);
+
+ self::assertCount(1, $oCell->getElements());
+ self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\Image', $element);
+ }
+
+ /**
+ * Add image header.
+ */
+ public function testAddImageHeader(): void
+ {
+ $src = __DIR__ . '/../_files/images/earth.jpg';
+ $oCell = new Cell('header', 1);
+ $element = $oCell->addImage($src);
+
+ self::assertCount(1, $oCell->getElements());
+ self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\Image', $element);
+ }
+
+ /**
+ * Add image footer.
+ */
+ public function testAddImageFooter(): void
+ {
+ $src = __DIR__ . '/../_files/images/earth.jpg';
+ $oCell = new Cell('footer', 1);
+ $element = $oCell->addImage($src);
+
+ self::assertCount(1, $oCell->getElements());
+ self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\Image', $element);
+ }
+
+ /**
+ * Add image section by URL.
+ */
+ public function testAddImageSectionByUrl(): void
+ {
+ $oCell = new Cell();
+ $element = $oCell->addImage(self::getRemoteGifImageUrl());
+
+ self::assertCount(1, $oCell->getElements());
+ self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\Image', $element);
+ }
+
+ /**
+ * Add object.
+ */
+ public function testAddObjectXLS(): void
+ {
+ $src = __DIR__ . '/../_files/documents/sheet.xls';
+ $oCell = new Cell();
+ $element = $oCell->addObject($src);
+
+ self::assertCount(1, $oCell->getElements());
+ self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\OLEObject', $element);
+ }
+
+ /**
+ * Test add object exception.
+ */
+ public function testAddObjectException(): void
+ {
+ $this->expectException(\PhpOffice\PhpWord\Exception\InvalidObjectException::class);
+ $src = __DIR__ . '/../_files/xsl/passthrough.xsl';
+ $oCell = new Cell();
+ $oCell->addObject($src);
+ }
+
+ /**
+ * Add preserve text.
+ */
+ public function testAddPreserveText(): void
+ {
+ $oCell = new Cell();
+ $oCell->setDocPart('Header', 1);
+ $element = $oCell->addPreserveText('text');
+
+ self::assertCount(1, $oCell->getElements());
+ self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\PreserveText', $element);
+ }
+
+ /**
+ * Add preserve text non-UTF8.
+ */
+ public function testAddPreserveTextNotUTF8(): void
+ {
+ $oCell = new Cell();
+ $oCell->setDocPart('Header', 1);
+ $element = $oCell->addPreserveText(utf8decode('ééé'));
+
+ self::assertCount(1, $oCell->getElements());
+ self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\PreserveText', $element);
+ self::assertEquals(['ééé'], $element->getText());
+ }
+
+ /**
+ * Add preserve text exception.
+ */
+ public function testAddPreserveTextException(): void
+ {
+ $this->expectException(BadMethodCallException::class);
+ $oCell = new Cell();
+ $oCell->setDocPart('TextRun', 1);
+ $oCell->addPreserveText('text');
+ }
+
+ /**
+ * Add text run.
+ */
+ public function testCreateTextRun(): void
+ {
+ $oCell = new Cell();
+ $element = $oCell->addTextRun();
+
+ self::assertCount(1, $oCell->getElements());
+ self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\TextRun', $element);
+ }
+
+ /**
+ * Add check box.
+ */
+ public function testAddCheckBox(): void
+ {
+ $oCell = new Cell();
+ $element = $oCell->addCheckBox(utf8decode('ééé'), utf8decode('ééé'));
+
+ self::assertCount(1, $oCell->getElements());
+ self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\CheckBox', $element);
+ }
+
+ /**
+ * Get elements.
+ */
+ public function testGetElements(): void
+ {
+ $oCell = new Cell();
+
+ self::assertIsArray($oCell->getElements());
+ }
+}
diff --git a/tests/PhpWordTests/Element/CheckBoxTest.php b/tests/PhpWordTests/Element/CheckBoxTest.php
new file mode 100644
index 0000000000..fbdbf36aa3
--- /dev/null
+++ b/tests/PhpWordTests/Element/CheckBoxTest.php
@@ -0,0 +1,88 @@
+getText());
+ self::assertInstanceOf('PhpOffice\\PhpWord\\Style\\Font', $oCheckBox->getFontStyle());
+ self::assertInstanceOf('PhpOffice\\PhpWord\\Style\\Paragraph', $oCheckBox->getParagraphStyle());
+ }
+
+ /**
+ * Get name and text.
+ */
+ public function testCheckBox(): void
+ {
+ $oCheckBox = new CheckBox('chkBox', 'CheckBox');
+
+ self::assertEquals('chkBox', $oCheckBox->getName());
+ self::assertEquals('CheckBox', $oCheckBox->getText());
+ }
+
+ /**
+ * Get font style.
+ */
+ public function testFont(): void
+ {
+ $oCheckBox = new CheckBox('chkBox', 'CheckBox', 'fontStyle');
+ self::assertEquals('fontStyle', $oCheckBox->getFontStyle());
+
+ $oCheckBox->setFontStyle(['bold' => true, 'italic' => true, 'size' => 16]);
+ self::assertInstanceOf('PhpOffice\\PhpWord\\Style\\Font', $oCheckBox->getFontStyle());
+ }
+
+ /**
+ * Font style as object.
+ */
+ public function testFontObject(): void
+ {
+ $font = new Font();
+ $oCheckBox = new CheckBox('chkBox', 'CheckBox', $font);
+ self::assertEquals($font, $oCheckBox->getFontStyle());
+ }
+
+ /**
+ * Get paragraph style.
+ */
+ public function testParagraph(): void
+ {
+ $oCheckBox = new CheckBox('chkBox', 'CheckBox', 'fontStyle', 'paragraphStyle');
+ self::assertEquals('paragraphStyle', $oCheckBox->getParagraphStyle());
+
+ $oCheckBox->setParagraphStyle(['alignment' => Jc::CENTER, 'spaceAfter' => 100]);
+ self::assertInstanceOf('PhpOffice\\PhpWord\\Style\\Paragraph', $oCheckBox->getParagraphStyle());
+ }
+}
diff --git a/tests/PhpWordTests/Element/CommentTest.php b/tests/PhpWordTests/Element/CommentTest.php
new file mode 100644
index 0000000000..f76316d890
--- /dev/null
+++ b/tests/PhpWordTests/Element/CommentTest.php
@@ -0,0 +1,138 @@
+setStartElement($oText);
+ $oComment->setEndElement($oText);
+
+ self::assertEquals($author, $oComment->getAuthor());
+ self::assertEquals($date, $oComment->getDate());
+ self::assertEquals($initials, $oComment->getInitials());
+ self::assertEquals($oText, $oComment->getStartElement());
+ 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.
+ */
+ public function testAddText(): void
+ {
+ $oComment = new Comment('Test User', new DateTime(), 'my_initials');
+ $element = $oComment->addText('text');
+
+ self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\Text', $element);
+ self::assertCount(1, $oComment->getElements());
+ self::assertEquals('text', $element->getText());
+ }
+
+ /**
+ * Get elements.
+ */
+ public function testGetElements(): void
+ {
+ $oComment = new Comment('Test User', new DateTime(), 'my_initials');
+
+ self::assertIsArray($oComment->getElements());
+ }
+
+ /**
+ * Set/get relation Id.
+ */
+ public function testRelationId(): void
+ {
+ $oComment = new Comment('Test User', new DateTime(), 'my_initials');
+
+ $iVal = mt_rand(1, 1000);
+ $oComment->setRelationId($iVal);
+ self::assertEquals($iVal, $oComment->getRelationId());
+ }
+
+ public function testExceptionOnCommentStartOnComment(): void
+ {
+ $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);
+ }
+
+ public function testExceptionOnCommentEndOnComment(): void
+ {
+ $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/PhpWordTests/Element/FieldTest.php b/tests/PhpWordTests/Element/FieldTest.php
new file mode 100644
index 0000000000..f624e9294d
--- /dev/null
+++ b/tests/PhpWordTests/Element/FieldTest.php
@@ -0,0 +1,146 @@
+getType());
+ }
+
+ /**
+ * New instance with type and properties.
+ */
+ public function testConstructWithTypeProperties(): void
+ {
+ $oField = new Field('DATE', ['dateformat' => 'd-M-yyyy']);
+
+ self::assertEquals('DATE', $oField->getType());
+ self::assertEquals(['dateformat' => 'd-M-yyyy'], $oField->getProperties());
+ }
+
+ /**
+ * New instance with type and properties and options.
+ */
+ public function testConstructWithTypePropertiesOptions(): void
+ {
+ $oField = new Field('DATE', ['dateformat' => 'd-M-yyyy'], ['SakaEraCalendar', 'PreserveFormat']);
+
+ self::assertEquals('DATE', $oField->getType());
+ self::assertEquals(['dateformat' => 'd-M-yyyy'], $oField->getProperties());
+ self::assertEquals(['SakaEraCalendar', 'PreserveFormat'], $oField->getOptions());
+ }
+
+ /**
+ * New instance with type and properties and options and text.
+ */
+ public function testConstructWithTypePropertiesOptionsText(): void
+ {
+ $oField = new Field('XE', [], ['Bold', 'Italic'], 'FieldValue');
+
+ self::assertEquals('XE', $oField->getType());
+ self::assertEquals([], $oField->getProperties());
+ self::assertEquals(['Bold', 'Italic'], $oField->getOptions());
+ self::assertEquals('FieldValue', $oField->getText());
+ }
+
+ /**
+ * New instance with type and properties and options and text as TextRun.
+ */
+ public function testConstructWithTypePropertiesOptionsTextAsTextRun(): void
+ {
+ $textRun = new TextRun();
+ $textRun->addText('test string');
+
+ $oField = new Field('XE', [], ['Bold', 'Italic'], $textRun);
+
+ self::assertEquals('XE', $oField->getType());
+ self::assertEquals([], $oField->getProperties());
+ self::assertEquals(['Bold', 'Italic'], $oField->getOptions());
+ self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\TextRun', $oField->getText());
+ }
+
+ public function testConstructWithOptionValue(): void
+ {
+ $oField = new Field('INDEX', [], ['\\c "3" \\h "A"']);
+
+ self::assertEquals('INDEX', $oField->getType());
+ self::assertEquals([], $oField->getProperties());
+ self::assertEquals(['\\c "3" \\h "A"'], $oField->getOptions());
+ }
+
+ /**
+ * Test setType exception.
+ */
+ public function testSetTypeException(): void
+ {
+ $this->expectException(InvalidArgumentException::class);
+ $this->expectExceptionMessage('Invalid type');
+ $object = new Field();
+ $object->setType('foo');
+ }
+
+ /**
+ * Test setProperties exception.
+ */
+ public function testSetPropertiesException(): void
+ {
+ $this->expectException(InvalidArgumentException::class);
+ $this->expectExceptionMessage('Invalid property');
+ $object = new Field('PAGE');
+ $object->setProperties(['foo' => 'bar']);
+ }
+
+ /**
+ * Test setOptions exception.
+ */
+ public function testSetOptionsException(): void
+ {
+ $this->expectException(InvalidArgumentException::class);
+ $this->expectExceptionMessage('Invalid option');
+ $object = new Field('PAGE');
+ $object->setOptions(['foo' => 'bar']);
+ }
+
+ /**
+ * Test setText exception.
+ */
+ public function testSetTextException(): void
+ {
+ $this->expectException(InvalidArgumentException::class);
+ $this->expectExceptionMessage('Invalid text');
+ $object = new Field('XE');
+ $object->setText([]);
+ }
+}
diff --git a/tests/PhpWordTests/Element/FooterTest.php b/tests/PhpWordTests/Element/FooterTest.php
new file mode 100644
index 0000000000..f97b159cb9
--- /dev/null
+++ b/tests/PhpWordTests/Element/FooterTest.php
@@ -0,0 +1,176 @@
+getSectionId());
+ }
+
+ /**
+ * Add text.
+ */
+ public function testAddText(): void
+ {
+ $oFooter = new Footer(1);
+ $element = $oFooter->addText('text');
+
+ self::assertCount(1, $oFooter->getElements());
+ self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\Text', $element);
+ }
+
+ /**
+ * Add text non-UTF8.
+ */
+ public function testAddTextNotUTF8(): void
+ {
+ $oFooter = new Footer(1);
+ $element = $oFooter->addText(utf8decode('ééé'));
+
+ self::assertCount(1, $oFooter->getElements());
+ self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\Text', $element);
+ self::assertEquals('ééé', $element->getText());
+ }
+
+ /**
+ * Add text break.
+ */
+ public function testAddTextBreak(): void
+ {
+ $oFooter = new Footer(1);
+ $iVal = mt_rand(1, 1000);
+ $oFooter->addTextBreak($iVal);
+
+ self::assertCount($iVal, $oFooter->getElements());
+ }
+
+ /**
+ * Add text run.
+ */
+ public function testCreateTextRun(): void
+ {
+ $oFooter = new Footer(1);
+ $element = $oFooter->addTextRun();
+
+ self::assertCount(1, $oFooter->getElements());
+ self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\TextRun', $element);
+ }
+
+ /**
+ * Add table.
+ */
+ public function testAddTable(): void
+ {
+ $oFooter = new Footer(1);
+ $element = $oFooter->addTable();
+
+ self::assertCount(1, $oFooter->getElements());
+ self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\Table', $element);
+ }
+
+ /**
+ * Add image.
+ */
+ public function testAddImage(): void
+ {
+ $src = __DIR__ . '/../_files/images/earth.jpg';
+ $oFooter = new Footer(1);
+ $element = $oFooter->addImage($src);
+
+ self::assertCount(1, $oFooter->getElements());
+ self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\Image', $element);
+ }
+
+ /**
+ * Add image by URL.
+ */
+ public function testAddImageByUrl(): void
+ {
+ $oFooter = new Footer(1);
+ $element = $oFooter->addImage(self::getRemoteGifImageUrl());
+
+ self::assertCount(1, $oFooter->getElements());
+ self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\Image', $element);
+ }
+
+ /**
+ * Add preserve text.
+ */
+ public function testAddPreserveText(): void
+ {
+ $oFooter = new Footer(1);
+ $element = $oFooter->addPreserveText('text');
+
+ self::assertCount(1, $oFooter->getElements());
+ self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\PreserveText', $element);
+ }
+
+ /**
+ * Add preserve text non-UTF8.
+ */
+ public function testAddPreserveTextNotUTF8(): void
+ {
+ $oFooter = new Footer(1);
+ $element = $oFooter->addPreserveText(utf8decode('ééé'));
+
+ self::assertCount(1, $oFooter->getElements());
+ self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\PreserveText', $element);
+ self::assertEquals(['ééé'], $element->getText());
+ }
+
+ /**
+ * Get elements.
+ */
+ public function testGetElements(): void
+ {
+ $oFooter = new Footer(1);
+
+ self::assertIsArray($oFooter->getElements());
+ }
+
+ /**
+ * Set/get relation Id.
+ */
+ public function testRelationID(): void
+ {
+ $oFooter = new Footer(0);
+
+ $iVal = mt_rand(1, 1000);
+ $oFooter->setRelationId($iVal);
+
+ self::assertEquals($iVal, $oFooter->getRelationId());
+ self::assertEquals(Footer::AUTO, $oFooter->getType());
+ }
+}
diff --git a/tests/PhpWordTests/Element/FootnoteTest.php b/tests/PhpWordTests/Element/FootnoteTest.php
new file mode 100644
index 0000000000..c6297cfc32
--- /dev/null
+++ b/tests/PhpWordTests/Element/FootnoteTest.php
@@ -0,0 +1,119 @@
+getElements());
+ self::assertNull($oFootnote->getParagraphStyle());
+ }
+
+ /**
+ * New instance with string parameter.
+ */
+ public function testConstructString(): void
+ {
+ $oFootnote = new Footnote('pStyle');
+
+ self::assertEquals('pStyle', $oFootnote->getParagraphStyle());
+ }
+
+ /**
+ * New instance with array parameter.
+ */
+ public function testConstructArray(): void
+ {
+ $oFootnote = new Footnote(['spacing' => 100]);
+
+ self::assertInstanceOf(
+ 'PhpOffice\\PhpWord\\Style\\Paragraph',
+ $oFootnote->getParagraphStyle()
+ );
+ }
+
+ /**
+ * Add text element.
+ */
+ public function testAddText(): void
+ {
+ $oFootnote = new Footnote();
+ $element = $oFootnote->addText('text');
+
+ self::assertCount(1, $oFootnote->getElements());
+ self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\Text', $element);
+ }
+
+ /**
+ * Add text break element.
+ */
+ public function testAddTextBreak(): void
+ {
+ $oFootnote = new Footnote();
+ $oFootnote->addTextBreak(2);
+
+ self::assertCount(2, $oFootnote->getElements());
+ }
+
+ /**
+ * Add link element.
+ */
+ public function testAddLink(): void
+ {
+ $oFootnote = new Footnote();
+ $element = $oFootnote->addLink('https://github.com/PHPOffice/PHPWord');
+
+ self::assertCount(1, $oFootnote->getElements());
+ self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\Link', $element);
+ }
+
+ /**
+ * Set/get reference Id.
+ */
+ public function testReferenceId(): void
+ {
+ $oFootnote = new Footnote();
+
+ $iVal = mt_rand(1, 1000);
+ $oFootnote->setRelationId($iVal);
+ self::assertEquals($iVal, $oFootnote->getRelationId());
+ }
+
+ /**
+ * Get elements.
+ */
+ public function testGetElements(): void
+ {
+ $oFootnote = new Footnote();
+ self::assertIsArray($oFootnote->getElements());
+ }
+}
diff --git a/tests/PhpWordTests/Element/FormulaTest.php b/tests/PhpWordTests/Element/FormulaTest.php
new file mode 100644
index 0000000000..dcb730e9cc
--- /dev/null
+++ b/tests/PhpWordTests/Element/FormulaTest.php
@@ -0,0 +1,54 @@
+add(new Element\Fraction(
+ new Element\Numeric(2),
+ new Element\Identifier('π')
+ ));
+
+ $element = new Formula(new Math());
+
+ self::assertEquals(new Math(), $element->getMath());
+ self::assertNotEquals($math, $element->getMath());
+
+ $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
new file mode 100644
index 0000000000..6d659dbd7c
--- /dev/null
+++ b/tests/PhpWordTests/Element/HeaderTest.php
@@ -0,0 +1,253 @@
+getSectionId());
+ self::assertEquals(Header::AUTO, $oHeader->getType());
+ }
+
+ /**
+ * Add text.
+ */
+ public function testAddText(): void
+ {
+ $oHeader = new Header(1);
+ $element = $oHeader->addText('text');
+
+ self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\Text', $element);
+ self::assertCount(1, $oHeader->getElements());
+ self::assertEquals('text', $element->getText());
+ }
+
+ /**
+ * Add text non-UTF8.
+ */
+ public function testAddTextNotUTF8(): void
+ {
+ $oHeader = new Header(1);
+ $element = $oHeader->addText(utf8decode('ééé'));
+
+ self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\Text', $element);
+ self::assertCount(1, $oHeader->getElements());
+ self::assertEquals('ééé', $element->getText());
+ }
+
+ /**
+ * Add text break.
+ */
+ public function testAddTextBreak(): void
+ {
+ $oHeader = new Header(1);
+ $oHeader->addTextBreak();
+ self::assertCount(1, $oHeader->getElements());
+ }
+
+ /**
+ * Add text break with params.
+ */
+ public function testAddTextBreakWithParams(): void
+ {
+ $oHeader = new Header(1);
+ $iVal = mt_rand(1, 1000);
+ $oHeader->addTextBreak($iVal);
+ self::assertCount($iVal, $oHeader->getElements());
+ }
+
+ /**
+ * Add text run.
+ */
+ public function testCreateTextRun(): void
+ {
+ $oHeader = new Header(1);
+ $element = $oHeader->addTextRun();
+ self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\TextRun', $element);
+ self::assertCount(1, $oHeader->getElements());
+ }
+
+ /**
+ * Add table.
+ */
+ public function testAddTable(): void
+ {
+ $oHeader = new Header(1);
+ $element = $oHeader->addTable();
+ self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\Table', $element);
+ self::assertCount(1, $oHeader->getElements());
+ }
+
+ /**
+ * Add image.
+ */
+ public function testAddImage(): void
+ {
+ $src = __DIR__ . '/../_files/images/earth.jpg';
+ $oHeader = new Header(1);
+ $element = $oHeader->addImage($src);
+
+ self::assertCount(1, $oHeader->getElements());
+ self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\Image', $element);
+ }
+
+ /**
+ * Add image by URL.
+ */
+ public function testAddImageByUrl(): void
+ {
+ $oHeader = new Header(1);
+ $element = $oHeader->addImage(self::getRemoteGifImageUrl());
+
+ self::assertCount(1, $oHeader->getElements());
+ self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\Image', $element);
+ }
+
+ /**
+ * Add preserve text.
+ */
+ public function testAddPreserveText(): void
+ {
+ $oHeader = new Header(1);
+ $element = $oHeader->addPreserveText('text');
+
+ self::assertCount(1, $oHeader->getElements());
+ self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\PreserveText', $element);
+ }
+
+ /**
+ * Add preserve text non-UTF8.
+ */
+ public function testAddPreserveTextNotUTF8(): void
+ {
+ $oHeader = new Header(1);
+ $element = $oHeader->addPreserveText(utf8decode('ééé'));
+
+ self::assertCount(1, $oHeader->getElements());
+ self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\PreserveText', $element);
+ self::assertEquals(['ééé'], $element->getText());
+ }
+
+ /**
+ * Add watermark.
+ */
+ public function testAddWatermark(): void
+ {
+ $src = __DIR__ . '/../_files/images/earth.jpg';
+ $oHeader = new Header(1);
+ $element = $oHeader->addWatermark($src);
+
+ self::assertCount(1, $oHeader->getElements());
+ self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\Image', $element);
+ }
+
+ /**
+ * Get elements.
+ */
+ public function testGetElements(): void
+ {
+ $oHeader = new Header(1);
+
+ self::assertIsArray($oHeader->getElements());
+ }
+
+ /**
+ * Set/get relation Id.
+ */
+ public function testRelationId(): void
+ {
+ $oHeader = new Header(1);
+
+ $iVal = mt_rand(1, 1000);
+ $oHeader->setRelationId($iVal);
+ self::assertEquals($iVal, $oHeader->getRelationId());
+ }
+
+ /**
+ * Reset type.
+ */
+ public function testResetType(): void
+ {
+ $oHeader = new Header(1);
+ $oHeader->firstPage();
+ $oHeader->resetType();
+
+ self::assertEquals(Header::AUTO, $oHeader->getType());
+ }
+
+ /**
+ * First page.
+ */
+ public function testFirstPage(): void
+ {
+ $oHeader = new Header(1);
+ $oHeader->firstPage();
+
+ self::assertEquals(Header::FIRST, $oHeader->getType());
+ }
+
+ /**
+ * Even page.
+ */
+ public function testEvenPage(): void
+ {
+ $oHeader = new Header(1);
+ $oHeader->evenPage();
+
+ self::assertEquals(Header::EVEN, $oHeader->getType());
+ }
+
+ /**
+ * Add footnote exception.
+ */
+ public function testAddFootnoteException(): void
+ {
+ $this->expectException(BadMethodCallException::class);
+ $header = new Header(1);
+ $header->addFootnote();
+ }
+
+ /**
+ * Set/get type.
+ */
+ public function testSetGetType(): void
+ {
+ $object = new Header(1);
+ self::assertEquals(Header::AUTO, $object->getType());
+
+ $object->setType('ODD');
+ self::assertEquals(Header::AUTO, $object->getType());
+ }
+}
diff --git a/tests/PhpWordTests/Element/ImageTest.php b/tests/PhpWordTests/Element/ImageTest.php
new file mode 100644
index 0000000000..f56b3da8a9
--- /dev/null
+++ b/tests/PhpWordTests/Element/ImageTest.php
@@ -0,0 +1,248 @@
+getSource());
+ self::assertEquals(md5($src), $oImage->getMediaId());
+ self::assertFalse($oImage->isWatermark());
+ self::assertEquals(Image::SOURCE_LOCAL, $oImage->getSourceType());
+ self::assertInstanceOf('PhpOffice\\PhpWord\\Style\\Image', $oImage->getStyle());
+ }
+
+ /**
+ * New instance with style.
+ */
+ public function testConstructWithStyle(): void
+ {
+ $src = __DIR__ . '/../_files/images/firefox.png';
+ $oImage = new Image(
+ $src,
+ [
+ 'width' => 210,
+ 'height' => 210,
+ 'alignment' => Jc::CENTER,
+ 'wrappingStyle' => \PhpOffice\PhpWord\Style\Image::WRAPPING_STYLE_BEHIND,
+ ]
+ );
+
+ self::assertInstanceOf('PhpOffice\\PhpWord\\Style\\Image', $oImage->getStyle());
+ }
+
+ /**
+ * Valid image types.
+ *
+ * @dataProvider providerImages
+ */
+ public function testImages($source, $type, $extension, $createFunction, $imageFunction, $imageQuality): void
+ {
+ $nam = ucfirst((string) strtok($source, '.'));
+ $source = __DIR__ . "/../_files/images/{$source}";
+ $image = new Image($source, null, null, $nam);
+ 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 static 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],
+ ];
+ }
+
+ /**
+ * Get style.
+ */
+ public function testStyle(): void
+ {
+ $oImage = new Image(
+ __DIR__ . '/../_files/images/earth.jpg',
+ ['height' => 210, 'alignment' => Jc::CENTER]
+ );
+
+ self::assertInstanceOf('PhpOffice\\PhpWord\\Style\\Image', $oImage->getStyle());
+ }
+
+ /**
+ * Test invalid local image.
+ */
+ public function testInvalidImageLocal(): void
+ {
+ $this->expectException(\PhpOffice\PhpWord\Exception\InvalidImageException::class);
+ new Image(__DIR__ . '/../_files/images/thisisnotarealimage');
+ }
+
+ /**
+ * Test invalid PHP Image.
+ */
+ public function testInvalidImagePhp(): void
+ {
+ $this->expectException(\PhpOffice\PhpWord\Exception\InvalidImageException::class);
+ $object = new Image('test.php');
+ $source = $object->getSource();
+ }
+
+ /**
+ * Test unsupported image.
+ */
+ public function testUnsupportedImage(): void
+ {
+ $this->expectException(\PhpOffice\PhpWord\Exception\UnsupportedImageTypeException::class);
+ //disable ssl verification, never do this in real application, you should pass the certificiate instead!!!
+ $arrContextOptions = [
+ 'ssl' => [
+ 'verify_peer' => false,
+ 'verify_peer_name' => false,
+ ],
+ ];
+ stream_context_set_default($arrContextOptions);
+ $object = new Image(self::getRemoteBmpImageUrl());
+ $source = $object->getSource();
+ }
+
+ /**
+ * Get relation Id.
+ */
+ public function testRelationID(): void
+ {
+ $oImage = new Image(__DIR__ . '/../_files/images/earth.jpg', ['width' => 100]);
+ $iVal = mt_rand(1, 1000);
+ $oImage->setRelationId($iVal);
+ self::assertEquals($iVal, $oImage->getRelationId());
+ }
+
+ /**
+ * Test archived image.
+ */
+ public function testArchivedImage(): void
+ {
+ $archiveFile = __DIR__ . '/../_files/documents/reader.docx';
+ $imageFile = 'word/media/image1.jpeg';
+ $image = new Image("zip://{$archiveFile}#{$imageFile}");
+ self::assertEquals('image/jpeg', $image->getImageType());
+ }
+
+ /**
+ * Test getting image as string.
+ */
+ public function testImageAsStringFromFile(): void
+ {
+ $image = new Image(__DIR__ . '/../_files/images/earth.jpg');
+
+ self::assertNotNull($image->getImageStringData());
+ self::assertNotNull($image->getImageStringData(true));
+ }
+
+ /**
+ * Test getting image from zip as string.
+ */
+ public function testImageAsStringFromZip(): void
+ {
+ $archiveFile = __DIR__ . '/../_files/documents/reader.docx';
+ $imageFile = 'word/media/image1.jpeg';
+ $image = new Image("zip://{$archiveFile}#{$imageFile}");
+
+ self::assertNotNull($image->getImageStringData());
+ self::assertNotNull($image->getImageStringData(true));
+ }
+
+ /**
+ * Test construct from string.
+ */
+ public function testConstructFromString(): void
+ {
+ $source = file_get_contents(__DIR__ . '/../_files/images/earth.jpg');
+
+ $image = new Image($source);
+ self::assertEquals($source, $image->getSource());
+ self::assertEquals(md5((string) $source), $image->getMediaId());
+ self::assertEquals('image/jpeg', $image->getImageType());
+ self::assertEquals('jpg', $image->getImageExtension());
+ self::assertEquals('imagecreatefromstring', $image->getImageCreateFunction());
+ self::assertNotNull($image->getImageFunction());
+ self::assertEquals(100, $image->getImageQuality());
+ self::assertTrue($image->isMemImage());
+
+ self::assertNotNull($image->getImageStringData());
+ self::assertNotNull($image->getImageStringData(true));
+ }
+
+ /**
+ * Test construct from GD.
+ */
+ public function testConstructFromGd(): void
+ {
+ $source = self::getRemoteImageUrl();
+
+ $image = new Image($source);
+ self::assertEquals($source, $image->getSource());
+ self::assertEquals(md5($source), $image->getMediaId());
+ self::assertEquals('image/png', $image->getImageType());
+ self::assertEquals('png', $image->getImageExtension());
+ self::assertEquals('imagecreatefrompng', $image->getImageCreateFunction());
+ self::assertNotNull($image->getImageFunction());
+ self::assertEquals(-1, $image->getImageQuality());
+ self::assertTrue($image->isMemImage());
+
+ self::assertNotNull($image->getImageStringData());
+ self::assertNotNull($image->getImageStringData(true));
+ }
+
+ /**
+ * Test invalid string image.
+ */
+ public function testInvalidImageString(): void
+ {
+ $this->expectException(\PhpOffice\PhpWord\Exception\InvalidImageException::class);
+ $object = new Image('this_is-a_non_valid_image');
+ $source = $object->getSource();
+ }
+}
diff --git a/tests/PhpWordTests/Element/LineTest.php b/tests/PhpWordTests/Element/LineTest.php
new file mode 100644
index 0000000000..f4a39b38d1
--- /dev/null
+++ b/tests/PhpWordTests/Element/LineTest.php
@@ -0,0 +1,77 @@
+getStyle());
+ }
+
+ /**
+ * Get style name.
+ */
+ public function testStyleText(): void
+ {
+ $oLine = new Line('lineStyle');
+
+ self::assertEquals('lineStyle', $oLine->getStyle());
+ }
+
+ /**
+ * Get style array.
+ */
+ public function testStyleArray(): void
+ {
+ $oLine = new Line(
+ [
+ '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,
+ ]
+ );
+
+ self::assertInstanceOf('PhpOffice\\PhpWord\\Style\\Line', $oLine->getStyle());
+ }
+}
diff --git a/tests/PhpWordTests/Element/LinkTest.php b/tests/PhpWordTests/Element/LinkTest.php
new file mode 100644
index 0000000000..5b5c6f77bf
--- /dev/null
+++ b/tests/PhpWordTests/Element/LinkTest.php
@@ -0,0 +1,86 @@
+getSource());
+ self::assertEquals($oLink->getSource(), $oLink->getText());
+ self::assertNull($oLink->getFontStyle());
+ self::assertNull($oLink->getParagraphStyle());
+ }
+
+ /**
+ * Create new instance with array.
+ */
+ public function testConstructWithParamsArray(): void
+ {
+ $oLink = new Link(
+ 'https://github.com/PHPOffice/PHPWord',
+ 'PHPWord on GitHub',
+ ['color' => '0000FF', 'underline' => Font::UNDERLINE_SINGLE],
+ ['marginLeft' => 600, 'marginRight' => 600, 'marginTop' => 600, 'marginBottom' => 600]
+ );
+
+ self::assertEquals('https://github.com/PHPOffice/PHPWord', $oLink->getSource());
+ self::assertEquals('PHPWord on GitHub', $oLink->getText());
+ self::assertInstanceOf('PhpOffice\\PhpWord\\Style\\Font', $oLink->getFontStyle());
+ self::assertInstanceOf('PhpOffice\\PhpWord\\Style\\Paragraph', $oLink->getParagraphStyle());
+ }
+
+ /**
+ * Create new instance with style name string.
+ */
+ public function testConstructWithParamsString(): void
+ {
+ $oLink = new Link('https://github.com/PHPOffice/PHPWord', null, 'fontStyle', 'paragraphStyle');
+
+ self::assertEquals('fontStyle', $oLink->getFontStyle());
+ self::assertEquals('paragraphStyle', $oLink->getParagraphStyle());
+ }
+
+ /**
+ * Set/get relation Id.
+ */
+ public function testRelationId(): void
+ {
+ $oLink = new Link('https://github.com/PHPOffice/PHPWord');
+
+ $iVal = mt_rand(1, 1000);
+ $oLink->setRelationId($iVal);
+ self::assertEquals($iVal, $oLink->getRelationId());
+ }
+}
diff --git a/tests/PhpWordTests/Element/ListItemRunTest.php b/tests/PhpWordTests/Element/ListItemRunTest.php
new file mode 100644
index 0000000000..69b5f990b0
--- /dev/null
+++ b/tests/PhpWordTests/Element/ListItemRunTest.php
@@ -0,0 +1,172 @@
+getElements());
+ self::assertInstanceOf('PhpOffice\\PhpWord\\Style\\Paragraph', $oListItemRun->getParagraphStyle());
+ }
+
+ /**
+ * New instance with string.
+ */
+ public function testConstructString(): void
+ {
+ $oListItemRun = new ListItemRun(0, null, 'pStyle');
+
+ self::assertCount(0, $oListItemRun->getElements());
+ self::assertEquals('pStyle', $oListItemRun->getParagraphStyle());
+ }
+
+ /**
+ * New instance with string.
+ */
+ public function testConstructListString(): void
+ {
+ $oListItemRun = new ListItemRun(0, 'numberingStyle');
+
+ self::assertCount(0, $oListItemRun->getElements());
+ }
+
+ /**
+ * New instance with array.
+ */
+ public function testConstructArray(): void
+ {
+ $oListItemRun = new ListItemRun(0, null, ['spacing' => 100]);
+
+ self::assertCount(0, $oListItemRun->getElements());
+ self::assertInstanceOf('PhpOffice\\PhpWord\\Style\\Paragraph', $oListItemRun->getParagraphStyle());
+ }
+
+ /**
+ * Get style.
+ */
+ public function testStyle(): void
+ {
+ $oListItemRun = new ListItemRun(1, ['listType' => \PhpOffice\PhpWord\Style\ListItem::TYPE_NUMBER]);
+
+ self::assertInstanceOf('PhpOffice\\PhpWord\\Style\\ListItem', $oListItemRun->getStyle());
+ self::assertEquals(\PhpOffice\PhpWord\Style\ListItem::TYPE_NUMBER, $oListItemRun->getStyle()->getListType());
+ }
+
+ /**
+ * getDepth.
+ */
+ public function testDepth(): void
+ {
+ $iVal = mt_rand(1, 1000);
+ $oListItemRun = new ListItemRun($iVal);
+
+ self::assertEquals($iVal, $oListItemRun->getDepth());
+ }
+
+ /**
+ * Add text.
+ */
+ public function testAddText(): void
+ {
+ $oListItemRun = new ListItemRun();
+ $element = $oListItemRun->addText('text');
+
+ self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\Text', $element);
+ self::assertCount(1, $oListItemRun->getElements());
+ self::assertEquals('text', $element->getText());
+ }
+
+ /**
+ * Add text non-UTF8.
+ */
+ public function testAddTextNotUTF8(): void
+ {
+ $oListItemRun = new ListItemRun();
+ $element = $oListItemRun->addText(utf8decode('ééé'));
+
+ self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\Text', $element);
+ self::assertCount(1, $oListItemRun->getElements());
+ self::assertEquals('ééé', $element->getText());
+ }
+
+ /**
+ * Add link.
+ */
+ public function testAddLink(): void
+ {
+ $oListItemRun = new ListItemRun();
+ $element = $oListItemRun->addLink('https://github.com/PHPOffice/PHPWord');
+
+ self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\Link', $element);
+ self::assertCount(1, $oListItemRun->getElements());
+ self::assertEquals('https://github.com/PHPOffice/PHPWord', $element->getSource());
+ }
+
+ /**
+ * Add link with name.
+ */
+ public function testAddLinkWithName(): void
+ {
+ $oListItemRun = new ListItemRun();
+ $element = $oListItemRun->addLink('https://github.com/PHPOffice/PHPWord', 'PHPWord on GitHub');
+
+ self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\Link', $element);
+ self::assertCount(1, $oListItemRun->getElements());
+ self::assertEquals('https://github.com/PHPOffice/PHPWord', $element->getSource());
+ self::assertEquals('PHPWord on GitHub', $element->getText());
+ }
+
+ /**
+ * Add text break.
+ */
+ public function testAddTextBreak(): void
+ {
+ $oListItemRun = new ListItemRun();
+ $oListItemRun->addTextBreak(2);
+
+ self::assertCount(2, $oListItemRun->getElements());
+ }
+
+ /**
+ * Add image.
+ */
+ public function testAddImage(): void
+ {
+ $src = __DIR__ . '/../_files/images/earth.jpg';
+
+ $oListItemRun = new ListItemRun();
+ $element = $oListItemRun->addImage($src);
+
+ self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\Image', $element);
+ self::assertCount(1, $oListItemRun->getElements());
+ }
+}
diff --git a/tests/PhpWord/Element/ListItemTest.php b/tests/PhpWordTests/Element/ListItemTest.php
similarity index 53%
rename from tests/PhpWord/Element/ListItemTest.php
rename to tests/PhpWordTests/Element/ListItemTest.php
index e5c815ec69..3da9a8d101 100644
--- a/tests/PhpWord/Element/ListItemTest.php
+++ b/tests/PhpWordTests/Element/ListItemTest.php
@@ -1,4 +1,5 @@
assertInstanceOf('PhpOffice\\PhpWord\\Element\\Text', $oListItem->getTextObject());
+ self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\Text', $oListItem->getTextObject());
}
/**
- * Get style
+ * Get style.
*/
- public function testStyle()
+ public function testStyle(): void
{
- $oListItem = new ListItem('text', 1, null, array('listType' => \PhpOffice\PhpWord\Style\ListItem::TYPE_NUMBER));
+ $oListItem = new ListItem('text', 1, null, ['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());
+ self::assertInstanceOf('PhpOffice\\PhpWord\\Style\\ListItem', $oListItem->getStyle());
+ self::assertEquals(\PhpOffice\PhpWord\Style\ListItem::TYPE_NUMBER, $oListItem->getStyle()->getListType());
}
/**
- * Get depth
+ * Get depth.
*/
- public function testDepth()
+ public function testDepth(): void
{
- $iVal = rand(1, 1000);
+ $iVal = mt_rand(1, 1000);
$oListItem = new ListItem('text', $iVal);
- $this->assertEquals($iVal, $oListItem->getDepth());
+ self::assertEquals($iVal, $oListItem->getDepth());
}
}
diff --git a/tests/PhpWordTests/Element/ObjectTest.php b/tests/PhpWordTests/Element/ObjectTest.php
new file mode 100644
index 0000000000..2ef05567bc
--- /dev/null
+++ b/tests/PhpWordTests/Element/ObjectTest.php
@@ -0,0 +1,104 @@
+getStyle());
+ self::assertEquals($src, $oObject->getSource());
+ }
+
+ /**
+ * Create new instance with supported files.
+ */
+ public function testConstructWithSupportedFilesLong(): void
+ {
+ $src = __DIR__ . '/../_files/documents/sheet.xls';
+ $oObject = new OLEObject($src);
+
+ self::assertInstanceOf('PhpOffice\\PhpWord\\Style\\Image', $oObject->getStyle());
+ self::assertEquals($src, $oObject->getSource());
+ }
+
+ /**
+ * Create new instance with non-supported files.
+ */
+ public function testConstructWithNotSupportedFiles(): void
+ {
+ $this->expectException(\PhpOffice\PhpWord\Exception\InvalidObjectException::class);
+ $src = __DIR__ . '/../_files/xsl/passthrough.xsl';
+ $oObject = new OLEObject($src);
+ $source = $oObject->getSource();
+ }
+
+ /**
+ * Create with style.
+ */
+ public function testConstructWithSupportedFilesAndStyle(): void
+ {
+ $src = __DIR__ . '/../_files/documents/sheet.xls';
+ $oObject = new OLEObject($src, ['width' => '230px']);
+
+ self::assertInstanceOf('PhpOffice\\PhpWord\\Style\\Image', $oObject->getStyle());
+ self::assertEquals($src, $oObject->getSource());
+ }
+
+ /**
+ * Set/get relation Id.
+ */
+ public function testRelationId(): void
+ {
+ $src = __DIR__ . '/../_files/documents/sheet.xls';
+ $oObject = new OLEObject($src);
+
+ $iVal = mt_rand(1, 1000);
+ $oObject->setRelationId($iVal);
+ self::assertEquals($iVal, $oObject->getRelationId());
+ }
+
+ /**
+ * Set/get image relation Id.
+ */
+ public function testImageRelationId(): void
+ {
+ $src = __DIR__ . '/../_files/documents/sheet.xls';
+ $oObject = new OLEObject($src);
+
+ $iVal = mt_rand(1, 1000);
+ $oObject->setImageRelationId($iVal);
+ self::assertEquals($iVal, $oObject->getImageRelationId());
+ }
+}
diff --git a/tests/PhpWordTests/Element/PreserveTextTest.php b/tests/PhpWordTests/Element/PreserveTextTest.php
new file mode 100644
index 0000000000..746db6aeee
--- /dev/null
+++ b/tests/PhpWordTests/Element/PreserveTextTest.php
@@ -0,0 +1,63 @@
+getText());
+ self::assertNull($oPreserveText->getFontStyle());
+ self::assertNull($oPreserveText->getParagraphStyle());
+ }
+
+ /**
+ * Create new instance with style name.
+ */
+ public function testConstructWithString(): void
+ {
+ $oPreserveText = new PreserveText('text', 'styleFont', 'styleParagraph');
+ self::assertEquals(['text'], $oPreserveText->getText());
+ self::assertEquals('styleFont', $oPreserveText->getFontStyle());
+ self::assertEquals('styleParagraph', $oPreserveText->getParagraphStyle());
+ }
+
+ /**
+ * Create new instance with array.
+ */
+ public function testConstructWithArray(): void
+ {
+ $oPreserveText = new PreserveText('text', ['size' => 16, 'color' => '1B2232'], ['alignment' => Jc::CENTER]);
+ self::assertInstanceOf('PhpOffice\\PhpWord\\Style\\Font', $oPreserveText->getFontStyle());
+ self::assertInstanceOf('PhpOffice\\PhpWord\\Style\\Paragraph', $oPreserveText->getParagraphStyle());
+ }
+}
diff --git a/tests/PhpWordTests/Element/RowTest.php b/tests/PhpWordTests/Element/RowTest.php
new file mode 100644
index 0000000000..6dc8335ffd
--- /dev/null
+++ b/tests/PhpWordTests/Element/RowTest.php
@@ -0,0 +1,68 @@
+getHeight());
+ self::assertIsArray($oRow->getCells());
+ self::assertCount(0, $oRow->getCells());
+ self::assertInstanceOf('PhpOffice\\PhpWord\\Style\\Row', $oRow->getStyle());
+ }
+
+ /**
+ * Create new instance with parameters.
+ */
+ public function testConstructWithParams(): void
+ {
+ $iVal = mt_rand(1, 1000);
+ $oRow = new Row($iVal, ['borderBottomSize' => 18, 'borderBottomColor' => '0000FF', 'bgColor' => '66BBFF']);
+
+ self::assertEquals($iVal, $oRow->getHeight());
+ self::assertInstanceOf('PhpOffice\\PhpWord\\Style\\Row', $oRow->getStyle());
+ }
+
+ /**
+ * Add cell.
+ */
+ public function testAddCell(): void
+ {
+ $oRow = new Row();
+ $element = $oRow->addCell();
+
+ self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\Cell', $element);
+ self::assertCount(1, $oRow->getCells());
+ }
+}
diff --git a/tests/PhpWordTests/Element/RubyTest.php b/tests/PhpWordTests/Element/RubyTest.php
new file mode 100644
index 0000000000..44d2e5ba3c
--- /dev/null
+++ b/tests/PhpWordTests/Element/RubyTest.php
@@ -0,0 +1,97 @@
+getBaseTextRun()->getText());
+ self::assertInstanceOf('PhpOffice\\PhpWord\\Style\\Paragraph', $ruby->getBaseTextRun()->getParagraphStyle());
+ self::assertEquals('', $ruby->getRubyTextRun()->getText());
+ self::assertInstanceOf('PhpOffice\\PhpWord\\Style\\Paragraph', $ruby->getRubyTextRun()->getParagraphStyle());
+ 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::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::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::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/PhpWord/Element/SDTTest.php b/tests/PhpWordTests/Element/SDTTest.php
similarity index 54%
rename from tests/PhpWord/Element/SDTTest.php
rename to tests/PhpWordTests/Element/SDTTest.php
index 2328dd76be..d7617160be 100644
--- a/tests/PhpWord/Element/SDTTest.php
+++ b/tests/PhpWordTests/Element/SDTTest.php
@@ -1,4 +1,5 @@
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());
+ self::assertEquals($type, $object->getType());
+ self::assertEquals($types, $object->getListItems());
+ self::assertEquals($value, $object->getValue());
+ self::assertEquals($alias, $object->getAlias());
+ self::assertEquals($tag, $object->getTag());
}
/**
- * Test set type exception
- *
- * @expectedException \InvalidArgumentException
- * @expectedExceptionMessage Invalid style value
+ * Test set type exception.
*/
- public function testSetTypeException()
+ public function testSetTypeException(): void
{
+ $this->expectException(InvalidArgumentException::class);
+ $this->expectExceptionMessage('Invalid style value');
$object = new SDT('comboBox');
$object->setType('foo');
}
/**
- * Test set type
+ * Test set type.
*/
- public function testSetTypeNull()
+ public function testSetTypeNull(): void
{
$object = new SDT('comboBox');
$object->setType(' ');
- $this->assertEquals('comboBox', $object->getType());
+ self::assertEquals('comboBox', $object->getType());
}
}
diff --git a/tests/PhpWord/Element/SectionTest.php b/tests/PhpWordTests/Element/SectionTest.php
similarity index 58%
rename from tests/PhpWord/Element/SectionTest.php
rename to tests/PhpWordTests/Element/SectionTest.php
index 83d1214e45..bf38a33300 100644
--- a/tests/PhpWord/Element/SectionTest.php
+++ b/tests/PhpWordTests/Element/SectionTest.php
@@ -1,4 +1,5 @@
assertInstanceOf('PhpOffice\\PhpWord\\Style\\Section', $section->getStyle());
+ self::assertInstanceOf('PhpOffice\\PhpWord\\Style\\Section', $section->getStyle());
}
- public function testConstructorWithArrayStyle()
+ public function testConstructorWithArrayStyle(): void
{
- $section = new Section(0, array('orientation' => 'landscape'));
+ $section = new Section(0, ['orientation' => 'landscape']);
$style = $section->getStyle();
- $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Section', $style);
- $this->assertEquals('landscape', $style->getOrientation());
+ self::assertInstanceOf('PhpOffice\\PhpWord\\Style\\Section', $style);
+ self::assertEquals('landscape', $style->getOrientation());
}
- public function testConstructorWithObjectStyle()
+ public function testConstructorWithObjectStyle(): void
{
$style = new SectionStyle();
$section = new Section(0, $style);
- $this->assertSame($style, $section->getStyle());
+ self::assertSame($style, $section->getStyle());
}
/**
* @covers ::setStyle
*/
- public function testSetStyle()
+ public function testSetStyle(): void
{
$expected = 'landscape';
$object = new Section(0);
- $object->setStyle(array('orientation' => $expected, 'foo' => null));
- $this->assertEquals($expected, $object->getStyle()->getOrientation());
+ $object->setStyle(['orientation' => $expected, 'foo' => null]);
+ self::assertEquals($expected, $object->getStyle()->getOrientation());
}
/**
* @coversNothing
*/
- public function testAddElements()
+ public function testAddElements(): void
{
$objectSource = __DIR__ . '/../_files/documents/reader.docx';
$imageSource = __DIR__ . '/../_files/images/PhpWord.png';
$section = new Section(0);
$section->setPhpWord(new PhpWord());
- $section->addText(utf8_decode('ä'));
- $section->addLink(utf8_decode('http://äää.com'), utf8_decode('ä'));
+ $section->addText(utf8decode('ä'));
+ $section->addLink(utf8decode('http://äää.com'), utf8decode('ä'));
$section->addTextBreak();
$section->addPageBreak();
$section->addTable();
- $section->addListItem(utf8_decode('ä'));
+ $section->addListItem(utf8decode('ä'));
$section->addObject($objectSource);
$section->addImage($imageSource);
- $section->addTitle(utf8_decode('ä'), 1);
+ $section->addTitle(utf8decode('ä'), 1);
$section->addTextRun();
$section->addFootnote();
- $section->addCheckBox(utf8_decode('chkä'), utf8_decode('Contentä'));
+ $section->addCheckBox(utf8decode('chkä'), utf8decode('Contentä'));
$section->addTOC();
$elementCollection = $section->getElements();
- $elementTypes = array(
+ $elementTypes = [
'Text',
'Link',
'TextBreak',
@@ -99,88 +105,88 @@ public function testAddElements()
'Footnote',
'CheckBox',
'TOC',
- );
+ ];
$elmCount = 0;
foreach ($elementTypes as $elementType) {
- $this->assertInstanceOf("PhpOffice\\PhpWord\\Element\\{$elementType}", $elementCollection[$elmCount]);
- $elmCount++;
+ self::assertInstanceOf("PhpOffice\\PhpWord\\Element\\{$elementType}", $elementCollection[$elmCount]);
+ ++$elmCount;
}
}
/**
* @coversNothing
- * @expectedException \PhpOffice\PhpWord\Exception\InvalidObjectException
*/
- public function testAddObjectException()
+ public function testAddObjectException(): void
{
+ $this->expectException(\PhpOffice\PhpWord\Exception\InvalidObjectException::class);
$source = __DIR__ . '/_files/xsl/passthrough.xsl';
$section = new Section(0);
$section->addObject($source);
}
/**
- * Add title with predefined style
+ * Add title with predefined style.
*
* @coversNothing
*/
- public function testAddTitleWithStyle()
+ public function testAddTitleWithStyle(): void
{
- Style::addTitleStyle(1, array('size' => 14));
+ Style::addTitleStyle(1, ['size' => 14]);
$section = new Section(0);
$section->setPhpWord(new PhpWord());
$section->addTitle('Test', 1);
$elementCollection = $section->getElements();
- $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Title', $elementCollection[0]);
+ self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\Title', $elementCollection[0]);
}
/**
- * @covers ::addHeader
* @covers ::addFooter
+ * @covers ::addHeader
* @covers ::hasDifferentFirstPage
*/
- public function testAddHeaderFooter()
+ public function testAddHeaderFooter(): void
{
$object = new Section(0);
- $elements = array('Header', 'Footer');
+ $elements = ['Header', 'Footer'];
foreach ($elements as $element) {
$method = "add{$element}";
- $this->assertInstanceOf("PhpOffice\\PhpWord\\Element\\{$element}", $object->$method());
+ self::assertInstanceOf("PhpOffice\\PhpWord\\Element\\{$element}", $object->$method());
}
- $this->assertFalse($object->hasDifferentFirstPage());
+ self::assertFalse($object->hasDifferentFirstPage());
}
/**
* @covers ::addHeader
* @covers ::hasDifferentFirstPage
*/
- public function testHasDifferentFirstPageFooter()
+ public function testHasDifferentFirstPageFooter(): void
{
$object = new Section(1);
$object->addFooter(Header::FIRST);
- $this->assertTrue($object->hasDifferentFirstPage());
+ self::assertTrue($object->hasDifferentFirstPage());
}
/**
* @covers ::addHeader
* @covers ::hasDifferentFirstPage
*/
- public function testHasDifferentFirstPage()
+ public function testHasDifferentFirstPage(): void
{
$object = new Section(1);
$header = $object->addHeader();
$header->setType(Header::FIRST);
- $this->assertTrue($object->hasDifferentFirstPage());
+ self::assertTrue($object->hasDifferentFirstPage());
}
/**
* @covers ::addHeader
- * @expectedException \Exception
- * @expectedExceptionMessage Invalid header/footer type.
*/
- public function testAddHeaderException()
+ public function testAddHeaderException(): void
{
+ $this->expectException(Exception::class);
+ $this->expectExceptionMessage('Invalid header/footer type.');
$object = new Section(1);
$object->addHeader('ODD');
}
@@ -188,31 +194,31 @@ public function testAddHeaderException()
/**
* @covers \PhpOffice\PhpWord\Element\AbstractContainer::removeElement
*/
- public function testRemoveElementByIndex()
+ public function testRemoveElementByIndex(): void
{
$section = new Section(1);
$section->addText('firstText');
$section->addText('secondText');
- $this->assertEquals(2, $section->countElements());
+ self::assertEquals(2, $section->countElements());
$section->removeElement(1);
- $this->assertEquals(1, $section->countElements());
+ self::assertEquals(1, $section->countElements());
}
/**
* @covers \PhpOffice\PhpWord\Element\AbstractContainer::removeElement
*/
- public function testRemoveElementByElement()
+ public function testRemoveElementByElement(): void
{
$section = new Section(1);
$firstText = $section->addText('firstText');
$secondText = $section->addText('secondText');
- $this->assertEquals(2, $section->countElements());
+ self::assertEquals(2, $section->countElements());
$section->removeElement($firstText);
- $this->assertEquals(1, $section->countElements());
- $this->assertEquals($secondText->getElementId(), $section->getElement(1)->getElementId());
+ self::assertEquals(1, $section->countElements());
+ self::assertEquals($secondText->getElementId(), $section->getElement(1)->getElementId());
}
}
diff --git a/tests/PhpWord/Element/TOCTest.php b/tests/PhpWordTests/Element/TOCTest.php
similarity index 53%
rename from tests/PhpWord/Element/TOCTest.php
rename to tests/PhpWordTests/Element/TOCTest.php
index 5f5f518f43..3770823f5f 100644
--- a/tests/PhpWord/Element/TOCTest.php
+++ b/tests/PhpWordTests/Element/TOCTest.php
@@ -1,4 +1,5 @@
9062,
- 'leader' => \PhpOffice\PhpWord\Style\Tab::TAB_LEADER_DOT,
- 'indent' => 200,
- );
- $object = new TOC(array('size' => 11), array('position' => $expected['position']));
+ 'leader' => \PhpOffice\PhpWord\Style\Tab::TAB_LEADER_DOT,
+ 'indent' => 200,
+ ];
+ $object = new TOC(['size' => 11], ['position' => $expected['position']]);
$tocStyle = $object->getStyleTOC();
- $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\TOC', $tocStyle);
- $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Font', $object->getStyleFont());
+ self::assertInstanceOf('PhpOffice\\PhpWord\\Style\\TOC', $tocStyle);
+ self::assertInstanceOf('PhpOffice\\PhpWord\\Style\\Font', $object->getStyleFont());
foreach ($expected as $key => $value) {
$method = "get{$key}";
- $this->assertEquals($value, $tocStyle->$method());
+ self::assertEquals($value, $tocStyle->$method());
}
}
/**
- * Construct with named font style
+ * Construct with named font style.
*/
- public function testConstructWithStyleName()
+ public function testConstructWithStyleName(): void
{
$object = new TOC('Font Style');
// $tocStyle = $object->getStyleTOC();
- $this->assertEquals('Font Style', $object->getStyleFont());
+ self::assertEquals('Font Style', $object->getStyleFont());
}
/**
- * Test when no PHPWord object is assigned:
+ * Test when no PHPWord object is assigned:.
*/
- public function testNoPhpWord()
+ public function testNoPhpWord(): void
{
$object = new TOC();
- $this->assertEmpty($object->getTitles());
- $this->assertNull($object->getPhpWord());
+ self::assertEmpty($object->getTitles());
+ self::assertNull($object->getPhpWord());
}
/**
- * Set/get minDepth and maxDepth
+ * Set/get minDepth and maxDepth.
*/
- public function testSetGetMinMaxDepth()
+ public function testSetGetMinMaxDepth(): void
{
- $titles = array(
+ $titles = [
'Heading 1' => 1,
'Heading 2' => 2,
'Heading 3' => 3,
'Heading 4' => 4,
- );
+ ];
$phpWord = new PhpWord();
foreach ($titles as $text => $depth) {
@@ -88,14 +91,14 @@ public function testSetGetMinMaxDepth()
}
$toc = new TOC();
$toc->setPhpWord($phpWord);
- $this->assertEquals(1, $toc->getMinDepth());
- $this->assertEquals(9, $toc->getMaxDepth());
+ self::assertEquals(1, $toc->getMinDepth());
+ self::assertEquals(9, $toc->getMaxDepth());
$toc->setMinDepth(2);
$toc->setMaxDepth(3);
$toc->getTitles();
- $this->assertEquals(2, $toc->getMinDepth());
- $this->assertEquals(3, $toc->getMaxDepth());
+ self::assertEquals(2, $toc->getMinDepth());
+ self::assertEquals(3, $toc->getMaxDepth());
}
}
diff --git a/tests/PhpWordTests/Element/TableTest.php b/tests/PhpWordTests/Element/TableTest.php
new file mode 100644
index 0000000000..0628d269e6
--- /dev/null
+++ b/tests/PhpWordTests/Element/TableTest.php
@@ -0,0 +1,111 @@
+getStyle());
+ self::assertNull($oTable->getWidth());
+ self::assertEquals([], $oTable->getRows());
+ self::assertCount(0, $oTable->getRows());
+ }
+
+ /**
+ * Get style name.
+ */
+ public function testStyleText(): void
+ {
+ $oTable = new Table('tableStyle');
+
+ self::assertEquals('tableStyle', $oTable->getStyle());
+ }
+
+ /**
+ * Get style array.
+ */
+ public function testStyleArray(): void
+ {
+ $oTable = new Table(['borderSize' => 6, 'borderColor' => '006699', 'cellMargin' => 80]);
+
+ self::assertInstanceOf('PhpOffice\\PhpWord\\Style\\Table', $oTable->getStyle());
+ }
+
+ /**
+ * Set/get width.
+ */
+ public function testWidth(): void
+ {
+ $oTable = new Table();
+ $iVal = mt_rand(1, 1000);
+ $oTable->setWidth($iVal);
+ self::assertEquals($iVal, $oTable->getWidth());
+ }
+
+ /**
+ * Add/get row.
+ */
+ public function testRow(): void
+ {
+ $oTable = new Table();
+ $element = $oTable->addRow();
+ self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\Row', $element);
+ self::assertCount(1, $oTable->getRows());
+ }
+
+ /**
+ * Add cell.
+ */
+ public function testCell(): void
+ {
+ $oTable = new Table();
+ $oTable->addRow();
+ $element = $oTable->addCell();
+ self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\Cell', $element);
+ }
+
+ /**
+ * Add cell.
+ */
+ public function testCountColumns(): void
+ {
+ $oTable = new Table();
+ $oTable->addRow();
+ $oTable->addCell();
+ self::assertEquals($oTable->countColumns(), 1);
+ $oTable->addCell();
+ $oTable->addCell();
+ self::assertEquals($oTable->countColumns(), 3);
+ }
+}
diff --git a/tests/PhpWord/Element/TextBoxTest.php b/tests/PhpWordTests/Element/TextBoxTest.php
similarity index 51%
rename from tests/PhpWord/Element/TextBoxTest.php
rename to tests/PhpWordTests/Element/TextBoxTest.php
index cd50acd4a6..9289d1ad47 100644
--- a/tests/PhpWord/Element/TextBoxTest.php
+++ b/tests/PhpWordTests/Element/TextBoxTest.php
@@ -1,4 +1,5 @@
assertInstanceOf('PhpOffice\\PhpWord\\Element\\TextBox', $oTextBox);
- $this->assertNull($oTextBox->getStyle());
+ self::assertNull($oTextBox->getStyle());
}
/**
- * Get style name
+ * Get style name.
*/
- public function testStyleText()
+ public function testStyleText(): void
{
$oTextBox = new TextBox('textBoxStyle');
- $this->assertEquals('textBoxStyle', $oTextBox->getStyle());
+ self::assertEquals('textBoxStyle', $oTextBox->getStyle());
}
/**
- * Get style array
+ * Get style array.
*/
- public function testStyleArray()
+ public function testStyleArray(): void
{
$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,
+ 'borderSize' => 1,
'borderColor' => '',
- )
+ ]
);
- $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\TextBox', $oTextBox->getStyle());
+ self::assertInstanceOf('PhpOffice\\PhpWord\\Style\\TextBox', $oTextBox->getStyle());
}
}
diff --git a/tests/PhpWord/Element/TextBreakTest.php b/tests/PhpWordTests/Element/TextBreakTest.php
similarity index 53%
rename from tests/PhpWord/Element/TextBreakTest.php
rename to tests/PhpWordTests/Element/TextBreakTest.php
index 13084c679a..10ca058180 100644
--- a/tests/PhpWord/Element/TextBreakTest.php
+++ b/tests/PhpWordTests/Element/TextBreakTest.php
@@ -1,4 +1,5 @@
assertNull($object->getFontStyle());
- $this->assertNull($object->getParagraphStyle());
+ self::assertNull($object->getFontStyle());
+ self::assertNull($object->getParagraphStyle());
}
/**
- * Construct with style object
+ * Construct with style object.
*/
- public function testConstructWithStyleObject()
+ public function testConstructWithStyleObject(): void
{
$fStyle = new Font();
$pStyle = new Paragraph();
$object = new TextBreak($fStyle, $pStyle);
- $this->assertEquals($fStyle, $object->getFontStyle());
- $this->assertEquals($pStyle, $object->getParagraphStyle());
+ self::assertEquals($fStyle, $object->getFontStyle());
+ self::assertEquals($pStyle, $object->getParagraphStyle());
}
/**
- * Construct with style array
+ * Construct with style array.
*/
- public function testConstructWithStyleArray()
+ public function testConstructWithStyleArray(): void
{
- $fStyle = array('size' => 12);
- $pStyle = array('spacing' => 240);
+ $fStyle = ['size' => 12];
+ $pStyle = ['spacing' => 240];
$object = new TextBreak($fStyle, $pStyle);
- $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Font', $object->getFontStyle());
- $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Paragraph', $object->getParagraphStyle());
+ self::assertInstanceOf('PhpOffice\\PhpWord\\Style\\Font', $object->getFontStyle());
+ self::assertInstanceOf('PhpOffice\\PhpWord\\Style\\Paragraph', $object->getParagraphStyle());
}
/**
- * Construct with style name
+ * Construct with style name.
*/
- public function testConstructWithStyleName()
+ public function testConstructWithStyleName(): void
{
$fStyle = 'fStyle';
$pStyle = 'pStyle';
$object = new TextBreak($fStyle, $pStyle);
- $this->assertEquals($fStyle, $object->getFontStyle());
- $this->assertEquals($pStyle, $object->getParagraphStyle());
+ self::assertEquals($fStyle, $object->getFontStyle());
+ self::assertEquals($pStyle, $object->getParagraphStyle());
}
}
diff --git a/tests/PhpWordTests/Element/TextRunTest.php b/tests/PhpWordTests/Element/TextRunTest.php
new file mode 100644
index 0000000000..b18eca99e4
--- /dev/null
+++ b/tests/PhpWordTests/Element/TextRunTest.php
@@ -0,0 +1,203 @@
+getElements());
+ self::assertInstanceOf('PhpOffice\\PhpWord\\Style\\Paragraph', $oTextRun->getParagraphStyle());
+ }
+
+ /**
+ * New instance with string.
+ */
+ public function testConstructString(): void
+ {
+ $oTextRun = new TextRun('pStyle');
+
+ self::assertCount(0, $oTextRun->getElements());
+ self::assertEquals('pStyle', $oTextRun->getParagraphStyle());
+ }
+
+ /**
+ * New instance with array.
+ */
+ public function testConstructArray(): void
+ {
+ $oTextRun = new TextRun(['spacing' => 100]);
+
+ self::assertCount(0, $oTextRun->getElements());
+ self::assertInstanceOf('PhpOffice\\PhpWord\\Style\\Paragraph', $oTextRun->getParagraphStyle());
+ }
+
+ /**
+ * New instance with object.
+ */
+ public function testConstructObject(): void
+ {
+ $oParagraphStyle = new Paragraph();
+ $oParagraphStyle->setAlignment(Jc::BOTH);
+ $oTextRun = new TextRun($oParagraphStyle);
+
+ self::assertCount(0, $oTextRun->getElements());
+ self::assertInstanceOf('PhpOffice\\PhpWord\\Style\\Paragraph', $oTextRun->getParagraphStyle());
+ self::assertEquals(Jc::BOTH, $oTextRun->getParagraphStyle()->getAlignment());
+ }
+
+ /**
+ * Add text.
+ */
+ public function testAddText(): void
+ {
+ $oTextRun = new TextRun();
+ $element = $oTextRun->addText('text');
+
+ self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\Text', $element);
+ self::assertCount(1, $oTextRun->getElements());
+ self::assertEquals('text', $element->getText());
+ }
+
+ /**
+ * Add text non-UTF8.
+ */
+ public function testAddTextNotUTF8(): void
+ {
+ $oTextRun = new TextRun();
+ $element = $oTextRun->addText(utf8decode('ééé'));
+
+ self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\Text', $element);
+ self::assertCount(1, $oTextRun->getElements());
+ self::assertEquals('ééé', $element->getText());
+ }
+
+ /**
+ * Add link.
+ */
+ public function testAddLink(): void
+ {
+ $oTextRun = new TextRun();
+ $element = $oTextRun->addLink('https://github.com/PHPOffice/PHPWord');
+
+ self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\Link', $element);
+ self::assertCount(1, $oTextRun->getElements());
+ self::assertEquals('https://github.com/PHPOffice/PHPWord', $element->getSource());
+ }
+
+ /**
+ * Add link with name.
+ */
+ public function testAddLinkWithName(): void
+ {
+ $oTextRun = new TextRun();
+ $element = $oTextRun->addLink('https://github.com/PHPOffice/PHPWord', 'PHPWord on GitHub');
+
+ self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\Link', $element);
+ self::assertCount(1, $oTextRun->getElements());
+ self::assertEquals('https://github.com/PHPOffice/PHPWord', $element->getSource());
+ self::assertEquals('PHPWord on GitHub', $element->getText());
+ }
+
+ /**
+ * Add text break.
+ */
+ public function testAddTextBreak(): void
+ {
+ $oTextRun = new TextRun();
+ $oTextRun->addTextBreak(2);
+
+ self::assertCount(2, $oTextRun->getElements());
+ }
+
+ /**
+ * Add image.
+ */
+ public function testAddImage(): void
+ {
+ $src = __DIR__ . '/../_files/images/earth.jpg';
+
+ $oTextRun = new TextRun();
+ $element = $oTextRun->addImage($src);
+
+ self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\Image', $element);
+ self::assertCount(1, $oTextRun->getElements());
+ }
+
+ /**
+ * Add footnote.
+ */
+ public function testCreateFootnote(): void
+ {
+ $oTextRun = new TextRun();
+ $oTextRun->setPhpWord(new PhpWord());
+ $element = $oTextRun->addFootnote();
+
+ self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\Footnote', $element);
+ self::assertCount(1, $oTextRun->getElements());
+ }
+
+ /**
+ * Get paragraph style.
+ */
+ public function testParagraph(): void
+ {
+ $oText = new TextRun('paragraphStyle');
+ self::assertEquals('paragraphStyle', $oText->getParagraphStyle());
+
+ $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/Element/TextTest.php b/tests/PhpWordTests/Element/TextTest.php
new file mode 100644
index 0000000000..693430a87f
--- /dev/null
+++ b/tests/PhpWordTests/Element/TextTest.php
@@ -0,0 +1,87 @@
+getText());
+ self::assertInstanceOf('PhpOffice\\PhpWord\\Style\\Font', $oText->getFontStyle());
+ self::assertInstanceOf('PhpOffice\\PhpWord\\Style\\Paragraph', $oText->getParagraphStyle());
+ }
+
+ /**
+ * Get text.
+ */
+ public function testText(): void
+ {
+ $oText = new Text('text');
+
+ self::assertEquals('text', $oText->getText());
+ }
+
+ /**
+ * Get font style.
+ */
+ public function testFont(): void
+ {
+ $oText = new Text('text', 'fontStyle');
+ self::assertEquals('fontStyle', $oText->getFontStyle());
+
+ $oText->setFontStyle(['bold' => true, 'italic' => true, 'size' => 16]);
+ self::assertInstanceOf('PhpOffice\\PhpWord\\Style\\Font', $oText->getFontStyle());
+ }
+
+ /**
+ * Get font style as object.
+ */
+ public function testFontObject(): void
+ {
+ $font = new Font();
+ $oText = new Text('text', $font);
+ self::assertEquals($font, $oText->getFontStyle());
+ }
+
+ /**
+ * Get paragraph style.
+ */
+ public function testParagraph(): void
+ {
+ $oText = new Text('text', 'fontStyle', 'paragraphStyle');
+ self::assertEquals('paragraphStyle', $oText->getParagraphStyle());
+
+ $oText->setParagraphStyle(['alignment' => Jc::CENTER, 'spaceAfter' => 100]);
+ self::assertInstanceOf('PhpOffice\\PhpWord\\Style\\Paragraph', $oText->getParagraphStyle());
+ }
+}
diff --git a/tests/PhpWordTests/Element/TitleTest.php b/tests/PhpWordTests/Element/TitleTest.php
new file mode 100644
index 0000000000..ab1e38102f
--- /dev/null
+++ b/tests/PhpWordTests/Element/TitleTest.php
@@ -0,0 +1,79 @@
+getText());
+ self::assertEquals(1, $title->getDepth());
+ self::assertNull($title->getPageNumber());
+ self::assertNull($title->getStyle());
+ }
+
+ /**
+ * Create new instance with TextRun.
+ */
+ public function testConstructWithTextRun(): void
+ {
+ $textRun = new TextRun();
+ $textRun->addText('text');
+ $title = new Title($textRun);
+
+ 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);
+
+ new Title(new PageBreak());
+ }
+
+ public function testConstructWithPageNumber(): void
+ {
+ $title = new Title('text', 1, 0);
+
+ self::assertEquals('text', $title->getText());
+ self::assertEquals(0, $title->getPageNumber());
+ self::assertNull($title->getStyle());
+ }
+}
diff --git a/tests/PhpWord/Element/TrackChangeTest.php b/tests/PhpWordTests/Element/TrackChangeTest.php
similarity index 58%
rename from tests/PhpWord/Element/TrackChangeTest.php
rename to tests/PhpWordTests/Element/TrackChangeTest.php
index b6cea92421..1d37fb3dd4 100644
--- a/tests/PhpWord/Element/TrackChangeTest.php
+++ b/tests/PhpWordTests/Element/TrackChangeTest.php
@@ -1,4 +1,5 @@
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());
+ self::assertEquals($author, $oTrackChange->getAuthor());
+ self::assertEquals($date, $oTrackChange->getDate());
+ self::assertEquals(TrackChange::INSERTED, $oTrackChange->getChangeType());
}
/**
- * New instance with invalid \DateTime (produced by \DateTime::createFromFormat(...))
+ * New instance with invalid \DateTime (produced by \DateTime::createFromFormat(...)).
*/
- public function testConstructDefaultWithInvalidDate()
+ public function testConstructDefaultWithInvalidDate(): void
{
$author = 'Test User';
$date = false;
@@ -54,9 +58,8 @@ public function testConstructDefaultWithInvalidDate()
$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());
+ self::assertEquals($author, $oTrackChange->getAuthor());
+ self::assertEquals($date, null);
+ self::assertEquals(TrackChange::INSERTED, $oTrackChange->getChangeType());
}
}
diff --git a/tests/PhpWordTests/Escaper/RtfEscaper2Test.php b/tests/PhpWordTests/Escaper/RtfEscaper2Test.php
new file mode 100644
index 0000000000..d65b543f21
--- /dev/null
+++ b/tests/PhpWordTests/Escaper/RtfEscaper2Test.php
@@ -0,0 +1,84 @@
+write());
+
+ return $txt2;
+ }
+
+ public function expect($str)
+ {
+ return self::HEADER . $str . self::TRAILER;
+ }
+
+ /**
+ * Test special characters which require escaping.
+ */
+ public function testSpecial(): void
+ {
+ $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
+ {
+ $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
+ {
+ $str = 'Hebrew - שלום';
+ $expect = $this->expect('Hebrew - \\uc0{\\u1513}\\uc0{\\u1500}\\uc0{\\u1493}\\uc0{\\u1501}');
+ self::assertEquals($expect, $this->escapestring($str));
+ }
+
+ /**
+ * Test tab.
+ */
+ public function testTab(): void
+ {
+ $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/Escaper/RtfEscaper3Test.php b/tests/PhpWordTests/Escaper/RtfEscaper3Test.php
new file mode 100644
index 0000000000..1aebea52f0
--- /dev/null
+++ b/tests/PhpWordTests/Escaper/RtfEscaper3Test.php
@@ -0,0 +1,96 @@
+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
+ {
+ Settings::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
+ {
+ 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));
+ }
+
+ /**
+ * Test Hebrew.
+ */
+ public function testHebrew(): void
+ {
+ Settings::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
+ {
+ 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/PhpWord/Exception/CopyFileExceptionTest.php b/tests/PhpWordTests/Exception/CopyFileExceptionTest.php
similarity index 78%
rename from tests/PhpWord/Exception/CopyFileExceptionTest.php
rename to tests/PhpWordTests/Exception/CopyFileExceptionTest.php
index 5fed9c9f25..9ca06d2b09 100644
--- a/tests/PhpWord/Exception/CopyFileExceptionTest.php
+++ b/tests/PhpWordTests/Exception/CopyFileExceptionTest.php
@@ -1,4 +1,5 @@
expectException(CopyFileException::class);
+
throw new CopyFileException('C:\source\dummy.txt', 'C:\destination\dummy.txt');
}
}
diff --git a/tests/PhpWord/Exception/CreateTemporaryFileExceptionTest.php b/tests/PhpWordTests/Exception/CreateTemporaryFileExceptionTest.php
similarity index 81%
rename from tests/PhpWord/Exception/CreateTemporaryFileExceptionTest.php
rename to tests/PhpWordTests/Exception/CreateTemporaryFileExceptionTest.php
index f879285e89..31015c62a8 100644
--- a/tests/PhpWord/Exception/CreateTemporaryFileExceptionTest.php
+++ b/tests/PhpWordTests/Exception/CreateTemporaryFileExceptionTest.php
@@ -1,4 +1,5 @@
expectException(CreateTemporaryFileException::class);
+
throw new CreateTemporaryFileException();
}
}
diff --git a/tests/PhpWord/Exception/ExceptionTest.php b/tests/PhpWordTests/Exception/ExceptionTest.php
similarity index 67%
rename from tests/PhpWord/Exception/ExceptionTest.php
rename to tests/PhpWordTests/Exception/ExceptionTest.php
index 8c7bce5774..09ee933c86 100644
--- a/tests/PhpWord/Exception/ExceptionTest.php
+++ b/tests/PhpWordTests/Exception/ExceptionTest.php
@@ -1,4 +1,5 @@
expectException(Exception::class);
+
throw new Exception();
}
}
diff --git a/tests/PhpWord/Exception/InvalidImageExceptionTest.php b/tests/PhpWordTests/Exception/InvalidImageExceptionTest.php
similarity index 80%
rename from tests/PhpWord/Exception/InvalidImageExceptionTest.php
rename to tests/PhpWordTests/Exception/InvalidImageExceptionTest.php
index 71da1aa9e3..dea167bb25 100644
--- a/tests/PhpWord/Exception/InvalidImageExceptionTest.php
+++ b/tests/PhpWordTests/Exception/InvalidImageExceptionTest.php
@@ -1,4 +1,5 @@
expectException(InvalidImageException::class);
+
throw new InvalidImageException();
}
}
diff --git a/tests/PhpWord/Exception/InvalidStyleExceptionTest.php b/tests/PhpWordTests/Exception/InvalidStyleExceptionTest.php
similarity index 80%
rename from tests/PhpWord/Exception/InvalidStyleExceptionTest.php
rename to tests/PhpWordTests/Exception/InvalidStyleExceptionTest.php
index 1d981449a9..7f2a1650e4 100644
--- a/tests/PhpWord/Exception/InvalidStyleExceptionTest.php
+++ b/tests/PhpWordTests/Exception/InvalidStyleExceptionTest.php
@@ -1,4 +1,5 @@
expectException(InvalidStyleException::class);
+
throw new InvalidStyleException();
}
}
diff --git a/tests/PhpWord/Exception/UnsupportedImageTypeExceptionTest.php b/tests/PhpWordTests/Exception/UnsupportedImageTypeExceptionTest.php
similarity index 74%
rename from tests/PhpWord/Exception/UnsupportedImageTypeExceptionTest.php
rename to tests/PhpWordTests/Exception/UnsupportedImageTypeExceptionTest.php
index 5b03f5e31d..2252b874ef 100644
--- a/tests/PhpWord/Exception/UnsupportedImageTypeExceptionTest.php
+++ b/tests/PhpWordTests/Exception/UnsupportedImageTypeExceptionTest.php
@@ -1,4 +1,5 @@
expectException(UnsupportedImageTypeException::class);
+
throw new UnsupportedImageTypeException();
}
}
diff --git a/tests/PhpWordTests/IOFactoryTest.php b/tests/PhpWordTests/IOFactoryTest.php
new file mode 100644
index 0000000000..6a8d746bd0
--- /dev/null
+++ b/tests/PhpWordTests/IOFactoryTest.php
@@ -0,0 +1,133 @@
+expectException(Exception::class);
+ IOFactory::createWriter(new PhpWord(), 'Word2006');
+ }
+
+ /**
+ * Create existing reader.
+ */
+ public function testExistingReaderCanBeCreated(): void
+ {
+ self::assertInstanceOf(
+ 'PhpOffice\\PhpWord\\Reader\\Word2007',
+ IOFactory::createReader('Word2007')
+ );
+ }
+
+ /**
+ * Create non-existing reader.
+ */
+ public function testNonexistentReaderCanNotBeCreated(): void
+ {
+ $this->expectException(Exception::class);
+ IOFactory::createReader('Word2006');
+ }
+
+ /**
+ * Load document.
+ */
+ public function testLoad(): void
+ {
+ $file = __DIR__ . '/_files/templates/blank.docx';
+ self::assertInstanceOf(
+ 'PhpOffice\\PhpWord\\PhpWord',
+ 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/PhpWord/MediaTest.php b/tests/PhpWordTests/MediaTest.php
similarity index 55%
rename from tests/PhpWord/MediaTest.php
rename to tests/PhpWordTests/MediaTest.php
index 3cf62b59f4..2eb60a858b 100644
--- a/tests/PhpWord/MediaTest.php
+++ b/tests/PhpWordTests/MediaTest.php
@@ -1,4 +1,5 @@
assertEquals(array(), Media::getElements('section'));
+ self::assertEquals([], Media::getElements('footer'));
}
/**
- * Count section media elements
+ * Count section media elements.
*/
- public function testCountSectionMediaElementsWithNull()
+ public function testCountSectionMediaElementsWithNull(): void
{
- $this->assertEquals(0, Media::countElements('section'));
+ self::assertEquals(0, Media::countElements('section'));
}
/**
- * Add section media element
+ * Add section media element.
*/
- public function testAddSectionMediaElement()
+ public function testAddSectionMediaElement(): void
{
$local = __DIR__ . '/_files/images/mars.jpg';
$object = __DIR__ . '/_files/documents/sheet.xls';
@@ -56,25 +75,25 @@ public function testAddSectionMediaElement()
Media::addElement('section', 'object', $object);
Media::addElement('section', 'object', $object);
- $this->assertCount(3, Media::getElements('section'));
+ self::assertCount(3, Media::getElements('section'));
}
/**
- * Add section link
+ * Add section link.
*/
- public function testAddSectionLinkElement()
+ public function testAddSectionLinkElement(): void
{
$expected = Media::countElements('section') + 1;
$actual = Media::addElement('section', 'link', 'http://test.com');
- $this->assertEquals($expected, $actual);
- $this->assertCount(1, Media::getElements('section', 'link'));
+ self::assertEquals($expected, $actual);
+ self::assertCount(1, Media::getElements('section', 'link'));
}
/**
- * Add header media element
+ * Add header media element.
*/
- public function testAddHeaderMediaElement()
+ public function testAddHeaderMediaElement(): void
{
$local = __DIR__ . '/_files/images/mars.jpg';
$remote = self::getRemoteImageUrl();
@@ -82,14 +101,14 @@ public function testAddHeaderMediaElement()
Media::addElement('header1', 'image', $local, new Image($local));
Media::addElement('header1', 'image', $remote, new Image($remote));
- $this->assertCount(2, Media::getElements('header1'));
- $this->assertEmpty(Media::getElements('header2'));
+ self::assertCount(2, Media::getElements('header1'));
+ self::assertEmpty(Media::getElements('header2'));
}
/**
- * Add footer media element and reset media
+ * Add footer media element and reset media.
*/
- public function testAddFooterMediaElement()
+ public function testAddFooterMediaElement(): void
{
$local = __DIR__ . '/_files/images/mars.jpg';
$remote = self::getRemoteImageUrl();
@@ -97,20 +116,19 @@ public function testAddFooterMediaElement()
Media::addElement('footer1', 'image', $local, new Image($local));
Media::addElement('footer1', 'image', $remote, new Image($remote));
- $this->assertCount(2, Media::getElements('footer1'));
+ self::assertCount(2, Media::getElements('footer1'));
Media::resetElements();
- $this->assertCount(0, Media::getElements('footer1'));
+ self::assertCount(0, Media::getElements('footer1'));
}
/**
- * Add image element exception
- *
- * @expectedException \Exception
- * @expectedExceptionMessage Image object not assigned.
+ * Add image element exception.
*/
- public function testAddElementImageException()
+ public function testAddElementImageException(): void
{
+ $this->expectException(Exception::class);
+ $this->expectExceptionMessage('Image object not assigned.');
Media::addElement('section', 'image', __DIR__ . '/_files/images/mars.jpg');
}
}
diff --git a/tests/PhpWordTests/Metadata/DocInfoTest.php b/tests/PhpWordTests/Metadata/DocInfoTest.php
new file mode 100644
index 0000000000..d5c9eb5124
--- /dev/null
+++ b/tests/PhpWordTests/Metadata/DocInfoTest.php
@@ -0,0 +1,229 @@
+setCreator();
+ self::assertEquals('', $oProperties->getCreator());
+
+ $oProperties->setCreator('AAA');
+ self::assertEquals('AAA', $oProperties->getCreator());
+ }
+
+ /**
+ * Last modified by.
+ */
+ public function testLastModifiedBy(): void
+ {
+ $oProperties = new DocInfo();
+ $oProperties->setLastModifiedBy();
+ self::assertEquals('', $oProperties->getLastModifiedBy());
+
+ $oProperties->setLastModifiedBy('AAA');
+ self::assertEquals('AAA', $oProperties->getLastModifiedBy());
+ }
+
+ /**
+ * Created.
+ */
+ public function testCreated(): void
+ {
+ $oProperties = new DocInfo();
+ $oProperties->setCreated();
+ self::assertEquals(time(), $oProperties->getCreated());
+
+ $iTime = time() + 3600;
+ $oProperties->setCreated($iTime);
+ self::assertEquals($iTime, $oProperties->getCreated());
+ }
+
+ /**
+ * Modified.
+ */
+ public function testModified(): void
+ {
+ $oProperties = new DocInfo();
+ $oProperties->setModified();
+ self::assertEquals(time(), $oProperties->getModified());
+
+ $iTime = time() + 3600;
+ $oProperties->setModified($iTime);
+ self::assertEquals($iTime, $oProperties->getModified());
+ }
+
+ /**
+ * Title.
+ */
+ public function testTitle(): void
+ {
+ $oProperties = new DocInfo();
+ $oProperties->setTitle();
+ self::assertEquals('', $oProperties->getTitle());
+
+ $oProperties->setTitle('AAA');
+ self::assertEquals('AAA', $oProperties->getTitle());
+ }
+
+ /**
+ * Description.
+ */
+ public function testDescription(): void
+ {
+ $oProperties = new DocInfo();
+ $oProperties->setDescription();
+ self::assertEquals('', $oProperties->getDescription());
+
+ $oProperties->setDescription('AAA');
+ self::assertEquals('AAA', $oProperties->getDescription());
+ }
+
+ /**
+ * Subject.
+ */
+ public function testSubject(): void
+ {
+ $oProperties = new DocInfo();
+ $oProperties->setSubject();
+ self::assertEquals('', $oProperties->getSubject());
+
+ $oProperties->setSubject('AAA');
+ self::assertEquals('AAA', $oProperties->getSubject());
+ }
+
+ /**
+ * Keywords.
+ */
+ public function testKeywords(): void
+ {
+ $oProperties = new DocInfo();
+ $oProperties->setKeywords();
+ self::assertEquals('', $oProperties->getKeywords());
+
+ $oProperties->setKeywords('AAA');
+ self::assertEquals('AAA', $oProperties->getKeywords());
+ }
+
+ /**
+ * Category.
+ */
+ public function testCategory(): void
+ {
+ $oProperties = new DocInfo();
+ $oProperties->setCategory();
+ self::assertEquals('', $oProperties->getCategory());
+
+ $oProperties->setCategory('AAA');
+ self::assertEquals('AAA', $oProperties->getCategory());
+ }
+
+ /**
+ * Company.
+ */
+ public function testCompany(): void
+ {
+ $oProperties = new DocInfo();
+ $oProperties->setCompany();
+ self::assertEquals('', $oProperties->getCompany());
+
+ $oProperties->setCompany('AAA');
+ self::assertEquals('AAA', $oProperties->getCompany());
+ }
+
+ /**
+ * Manager.
+ */
+ public function testManager(): void
+ {
+ $oProperties = new DocInfo();
+ $oProperties->setManager();
+ self::assertEquals('', $oProperties->getManager());
+
+ $oProperties->setManager('AAA');
+ self::assertEquals('AAA', $oProperties->getManager());
+ }
+
+ /**
+ * Custom properties.
+ */
+ public function testCustomProperty(): void
+ {
+ $oProperties = new DocInfo();
+ $oProperties->setCustomProperty('key1', null);
+ $oProperties->setCustomProperty('key2', true);
+ $oProperties->setCustomProperty('key3', 3);
+ $oProperties->setCustomProperty('key4', 4.4);
+ $oProperties->setCustomProperty('key5', 'value5');
+ self::assertEquals(DocInfo::PROPERTY_TYPE_STRING, $oProperties->getCustomPropertyType('key1'));
+ self::assertEquals(DocInfo::PROPERTY_TYPE_BOOLEAN, $oProperties->getCustomPropertyType('key2'));
+ self::assertEquals(DocInfo::PROPERTY_TYPE_INTEGER, $oProperties->getCustomPropertyType('key3'));
+ self::assertEquals(DocInfo::PROPERTY_TYPE_FLOAT, $oProperties->getCustomPropertyType('key4'));
+ self::assertEquals(DocInfo::PROPERTY_TYPE_STRING, $oProperties->getCustomPropertyType('key5'));
+ self::assertNull($oProperties->getCustomPropertyType('key6'));
+ self::assertNull($oProperties->getCustomPropertyValue('key1'));
+ self::assertTrue($oProperties->getCustomPropertyValue('key2'));
+ self::assertEquals(3, $oProperties->getCustomPropertyValue('key3'));
+ self::assertEquals(4.4, $oProperties->getCustomPropertyValue('key4'));
+ self::assertEquals('value5', $oProperties->getCustomPropertyValue('key5'));
+ self::assertNull($oProperties->getCustomPropertyValue('key6'));
+ self::assertTrue($oProperties->isCustomPropertySet('key5'));
+ self::assertNotTrue($oProperties->isCustomPropertySet('key6'));
+ self::assertEquals(['key1', 'key2', 'key3', 'key4', 'key5'], $oProperties->getCustomProperties());
+ }
+
+ /**
+ * Convert property.
+ */
+ public function testConvertProperty(): void
+ {
+ self::assertEquals('', DocInfo::convertProperty('a', 'empty'));
+ self::assertNull(DocInfo::convertProperty('a', 'null'));
+ self::assertEquals(8, DocInfo::convertProperty('8', 'int'));
+ self::assertEquals(8, DocInfo::convertProperty('8.3', 'uint'));
+ self::assertEquals(8.3, DocInfo::convertProperty('8.3', 'decimal'));
+ self::assertEquals('8.3', DocInfo::convertProperty('8.3', 'lpstr'));
+ self::assertEquals(strtotime('10/11/2013'), DocInfo::convertProperty('10/11/2013', 'date'));
+ self::assertTrue(DocInfo::convertProperty('true', 'bool'));
+ self::assertNotTrue(DocInfo::convertProperty('1', 'bool'));
+ self::assertEquals('1', DocInfo::convertProperty('1', 'array'));
+ self::assertEquals('1', DocInfo::convertProperty('1', ''));
+
+ self::assertEquals(DocInfo::PROPERTY_TYPE_INTEGER, DocInfo::convertPropertyType('int'));
+ self::assertEquals(DocInfo::PROPERTY_TYPE_INTEGER, DocInfo::convertPropertyType('uint'));
+ self::assertEquals(DocInfo::PROPERTY_TYPE_FLOAT, DocInfo::convertPropertyType('decimal'));
+ self::assertEquals(DocInfo::PROPERTY_TYPE_STRING, DocInfo::convertPropertyType('lpstr'));
+ self::assertEquals(DocInfo::PROPERTY_TYPE_DATE, DocInfo::convertPropertyType('date'));
+ self::assertEquals(DocInfo::PROPERTY_TYPE_BOOLEAN, DocInfo::convertPropertyType('bool'));
+ self::assertEquals(DocInfo::PROPERTY_TYPE_UNKNOWN, DocInfo::convertPropertyType('array'));
+ self::assertEquals(DocInfo::PROPERTY_TYPE_UNKNOWN, DocInfo::convertPropertyType(''));
+ }
+}
diff --git a/tests/PhpWordTests/Metadata/SettingsTest.php b/tests/PhpWordTests/Metadata/SettingsTest.php
new file mode 100644
index 0000000000..0c5a6f1593
--- /dev/null
+++ b/tests/PhpWordTests/Metadata/SettingsTest.php
@@ -0,0 +1,246 @@
+setEvenAndOddHeaders(true);
+ self::assertTrue($oSettings->hasEvenAndOddHeaders());
+ }
+
+ /**
+ * HideGrammaticalErrors.
+ */
+ public function testHideGrammaticalErrors(): void
+ {
+ $oSettings = new Settings();
+ $oSettings->setHideGrammaticalErrors(true);
+ self::assertTrue($oSettings->hasHideGrammaticalErrors());
+ }
+
+ /**
+ * HideSpellingErrors.
+ */
+ public function testHideSpellingErrors(): void
+ {
+ $oSettings = new Settings();
+ $oSettings->setHideSpellingErrors(true);
+ self::assertTrue($oSettings->hasHideSpellingErrors());
+ }
+
+ /**
+ * DocumentProtection.
+ */
+ public function testDocumentProtection(): void
+ {
+ $oSettings = new Settings();
+ $oSettings->setDocumentProtection(new Protection('trackedChanges'));
+ self::assertNotNull($oSettings->getDocumentProtection());
+
+ self::assertEquals('trackedChanges', $oSettings->getDocumentProtection()->getEditing());
+ }
+
+ /**
+ * Test setting an invalid salt.
+ */
+ public function testInvalidSalt(): void
+ {
+ $this->expectException(InvalidArgumentException::class);
+ $protection = new Protection();
+ $protection->setSalt('123');
+ }
+
+ /**
+ * TrackRevistions.
+ */
+ public function testTrackRevisions(): void
+ {
+ $oSettings = new Settings();
+ $oSettings->setTrackRevisions(true);
+ self::assertTrue($oSettings->hasTrackRevisions());
+ }
+
+ /**
+ * DoNotTrackFormatting.
+ */
+ public function testDoNotTrackFormatting(): void
+ {
+ $oSettings = new Settings();
+ $oSettings->setDoNotTrackFormatting(true);
+ self::assertTrue($oSettings->hasDoNotTrackFormatting());
+ }
+
+ /**
+ * DoNotTrackMoves.
+ */
+ public function testDoNotTrackMoves(): void
+ {
+ $oSettings = new Settings();
+ $oSettings->setDoNotTrackMoves(true);
+ self::assertTrue($oSettings->hasDoNotTrackMoves());
+ }
+
+ /**
+ * ProofState.
+ */
+ public function testProofState(): void
+ {
+ $proofState = new ProofState();
+ $proofState->setGrammar(ProofState::CLEAN);
+ $proofState->setSpelling(ProofState::DIRTY);
+
+ $oSettings = new Settings();
+ $oSettings->setProofState($proofState);
+ self::assertNotNull($oSettings->getProofState());
+ self::assertEquals(ProofState::CLEAN, $oSettings->getProofState()->getGrammar());
+ self::assertEquals(ProofState::DIRTY, $oSettings->getProofState()->getSpelling());
+ }
+
+ public function testWrongProofStateGrammar(): void
+ {
+ $this->expectException(InvalidArgumentException::class);
+ $proofState = new ProofState();
+ $proofState->setGrammar('wrong');
+ }
+
+ public function testWrongProofStateSpelling(): void
+ {
+ $this->expectException(InvalidArgumentException::class);
+ $proofState = new ProofState();
+ $proofState->setSpelling('wrong');
+ }
+
+ /**
+ * Zoom as percentage.
+ */
+ public function testZoomPercentage(): void
+ {
+ $oSettings = new Settings();
+ $oSettings->setZoom(75);
+ self::assertEquals(75, $oSettings->getZoom());
+ }
+
+ /**
+ * Zoom as string.
+ */
+ public function testZoomEnum(): void
+ {
+ $oSettings = new Settings();
+ $oSettings->setZoom(Zoom::FULL_PAGE);
+ self::assertEquals('fullPage', $oSettings->getZoom());
+ }
+
+ /**
+ * Test Update Fields on update.
+ */
+ public function testUpdateFields(): void
+ {
+ $oSettings = new Settings();
+ $oSettings->setUpdateFields(true);
+ self::assertTrue($oSettings->hasUpdateFields());
+ }
+
+ public function testAutoHyphenation(): void
+ {
+ $oSettings = new Settings();
+ $oSettings->setAutoHyphenation(true);
+ self::assertTrue($oSettings->hasAutoHyphenation());
+ }
+
+ public function testDefaultAutoHyphenation(): void
+ {
+ $oSettings = new Settings();
+ self::assertNull($oSettings->hasAutoHyphenation());
+ }
+
+ public function testConsecutiveHyphenLimit(): void
+ {
+ $consecutiveHypenLimit = 2;
+ $oSettings = new Settings();
+ $oSettings->setConsecutiveHyphenLimit($consecutiveHypenLimit);
+ self::assertSame($consecutiveHypenLimit, $oSettings->getConsecutiveHyphenLimit());
+ }
+
+ public function testDefaultConsecutiveHyphenLimit(): void
+ {
+ $oSettings = new Settings();
+ self::assertNull($oSettings->getConsecutiveHyphenLimit());
+ }
+
+ public function testHyphenationZone(): void
+ {
+ $hyphenationZoneInTwip = 100;
+ $oSettings = new Settings();
+ $oSettings->setHyphenationZone($hyphenationZoneInTwip);
+ self::assertSame($hyphenationZoneInTwip, $oSettings->getHyphenationZone());
+ }
+
+ public function testDefaultHyphenationZone(): void
+ {
+ $oSettings = new Settings();
+ self::assertNull($oSettings->getHyphenationZone());
+ }
+
+ public function testDoNotHyphenateCaps(): void
+ {
+ $oSettings = new Settings();
+ $oSettings->setDoNotHyphenateCaps(true);
+ self::assertTrue($oSettings->hasDoNotHyphenateCaps());
+ }
+
+ public function testDefaultDoNotHyphenateCaps(): void
+ {
+ $oSettings = new Settings();
+ self::assertNull($oSettings->hasDoNotHyphenateCaps());
+ }
+
+ public function testBookFoldPrinting(): void
+ {
+ $oSettings = new Settings();
+
+ $oSettings->setBookFoldPrinting(true);
+ self::assertTrue($oSettings->hasBookFoldPrinting());
+
+ $oSettings->setBookFoldPrinting(false);
+ self::assertFalse($oSettings->hasBookFoldPrinting());
+ }
+
+ public function testDefaultBookFoldPrinting(): void
+ {
+ $oSettings = new Settings();
+ self::assertFalse($oSettings->hasBookFoldPrinting());
+ }
+}
diff --git a/tests/PhpWordTests/PhpWordTest.php b/tests/PhpWordTests/PhpWordTest.php
new file mode 100644
index 0000000000..76919bbdf3
--- /dev/null
+++ b/tests/PhpWordTests/PhpWordTest.php
@@ -0,0 +1,240 @@
+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());
+ }
+
+ /**
+ * Test create/get section.
+ */
+ public function testCreateGetSections(): void
+ {
+ $phpWord = new PhpWord();
+ $phpWord->addSection();
+ self::assertCount(1, $phpWord->getSections());
+ }
+
+ /**
+ * Test set/get default font name.
+ */
+ public function testSetGetDefaultFontName(): void
+ {
+ $phpWord = new PhpWord();
+ $fontName = 'Times New Roman';
+ self::assertEquals(Settings::DEFAULT_FONT_NAME, $phpWord->getDefaultFontName());
+ $phpWord->setDefaultFontName($fontName);
+ self::assertEquals($fontName, $phpWord->getDefaultFontName());
+ }
+
+ /**
+ * Test set/get default font size.
+ */
+ public function testSetGetDefaultFontSize(): void
+ {
+ $phpWord = new PhpWord();
+ $fontSize = 16;
+ self::assertEquals(Settings::DEFAULT_FONT_SIZE, $phpWord->getDefaultFontSize());
+ $phpWord->setDefaultFontSize($fontSize);
+ 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/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.
+ */
+ public function testSetDefaultParagraphStyle(): void
+ {
+ $phpWord = new PhpWord();
+ $phpWord->setDefaultParagraphStyle([]);
+ self::assertInstanceOf('PhpOffice\\PhpWord\\Style\\Paragraph', Style::getStyle('Normal'));
+ }
+
+ /**
+ * Test add styles.
+ */
+ public function testAddStyles(): void
+ {
+ $phpWord = new PhpWord();
+ $styles = [
+ 'Paragraph' => 'Paragraph',
+ 'Font' => 'Font',
+ 'Table' => 'Table',
+ 'Link' => 'Font',
+ ];
+ foreach ($styles as $key => $value) {
+ $method = "add{$key}Style";
+ $styleId = "{$key} Style";
+ $phpWord->$method($styleId, []);
+ self::assertInstanceOf("PhpOffice\\PhpWord\\Style\\{$value}", Style::getStyle($styleId));
+ }
+ }
+
+ /**
+ * Test add title style.
+ */
+ public function testAddTitleStyle(): void
+ {
+ $phpWord = new PhpWord();
+ $titleLevel = 1;
+ $titleName = "Heading_{$titleLevel}";
+ $phpWord->addTitleStyle($titleLevel, []);
+ self::assertInstanceOf('PhpOffice\\PhpWord\\Style\\Font', Style::getStyle($titleName));
+ }
+
+ /**
+ * Test save.
+ */
+ public function testSave(): 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);
+ }
+
+ /**
+ * Test calling undefined method.
+ */
+ public function testCallUndefinedMethod(): void
+ {
+ $this->expectException(BadMethodCallException::class);
+ $this->expectExceptionMessage('is not defined');
+ $phpWord = new PhpWord();
+ $phpWord->undefinedMethod();
+ }
+
+ /**
+ * @covers \PhpOffice\PhpWord\PhpWord::getSection
+ */
+ public function testGetNotExistingSection(): void
+ {
+ $phpWord = new PhpWord();
+ $section = $phpWord->getSection(0);
+
+ self::assertNull($section);
+ }
+
+ /**
+ * @covers \PhpOffice\PhpWord\PhpWord::getSection
+ */
+ public function testGetSection(): void
+ {
+ $phpWord = new PhpWord();
+ $phpWord->addSection();
+ $section = $phpWord->getSection(0);
+
+ self::assertNotNull($section);
+ }
+
+ /**
+ * @covers \PhpOffice\PhpWord\PhpWord::sortSections
+ */
+ public function testSortSections(): void
+ {
+ $phpWord = new PhpWord();
+ $section1 = $phpWord->addSection();
+ $section1->addText('test1');
+ $section2 = $phpWord->addSection();
+ $section2->addText('test2');
+ $section2->addText('test3');
+
+ self::assertEquals(1, $phpWord->getSection(0)->countElements());
+ self::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;
+ });
+
+ self::assertEquals(2, $phpWord->getSection(0)->countElements());
+ self::assertEquals(1, $phpWord->getSection(1)->countElements());
+ }
+
+ /**
+ * @covers \PhpOffice\PhpWord\PhpWord::getSettings
+ */
+ public function testGetSettings(): void
+ {
+ $phpWord = new PhpWord();
+ self::assertInstanceOf('PhpOffice\\PhpWord\\Metadata\\Settings', $phpWord->getSettings());
+ }
+}
diff --git a/tests/PhpWord/Reader/HTMLTest.php b/tests/PhpWordTests/Reader/HTMLTest.php
similarity index 72%
rename from tests/PhpWord/Reader/HTMLTest.php
rename to tests/PhpWordTests/Reader/HTMLTest.php
index 38588afc17..7a35a06f78 100644
--- a/tests/PhpWord/Reader/HTMLTest.php
+++ b/tests/PhpWordTests/Reader/HTMLTest.php
@@ -1,4 +1,5 @@
assertInstanceOf('PhpOffice\\PhpWord\\PhpWord', $phpWord);
+ self::assertInstanceOf('PhpOffice\\PhpWord\\PhpWord', $phpWord);
}
/**
- * Test load exception
- *
- * @expectedException \Exception
- * @expectedExceptionMessage Cannot read
+ * Test load exception.
*/
- public function testLoadException()
+ public function testLoadException(): void
{
+ $this->expectException(Exception::class);
+ $this->expectExceptionMessage('Cannot read');
$filename = __DIR__ . '/../_files/documents/foo.html';
IOFactory::load($filename, 'HTML');
}
diff --git a/tests/PhpWordTests/Reader/MsDocTest.php b/tests/PhpWordTests/Reader/MsDocTest.php
new file mode 100644
index 0000000000..3552271823
--- /dev/null
+++ b/tests/PhpWordTests/Reader/MsDocTest.php
@@ -0,0 +1,155 @@
+canRead($filename));
+ }
+
+ /**
+ * Can read exception.
+ */
+ public function testCanReadFailed(): void
+ {
+ $object = new MsDoc();
+ $filename = __DIR__ . '/../_files/documents/foo.doc';
+ self::assertFalse($object->canRead($filename));
+ }
+
+ public function testLoadBasic(): void
+ {
+ $filename = __DIR__ . '/../_files/documents/reader.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('Welcome to PhpWord', $element0->getText());
+ }
+
+ public function testLoadHalfPointFont(): void
+ {
+ $filename = __DIR__ . '/../_files/documents/reader.font-halfpoint.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');
+ }
+ }
+
+ 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.
+ */
+ public function testFailIfFileNotReadable(): void
+ {
+ $this->expectException(Exception::class);
+ $filename = __DIR__ . '/../_files/documents/not_existing_reader.doc';
+ IOFactory::load($filename, 'MsDoc');
+ }
+
+ /**
+ * Test exception on non OLE document.
+ */
+ public function testFailIfFileNotOle(): void
+ {
+ $this->expectException(Exception::class);
+ $filename = __DIR__ . '/../_files/documents/reader.odt';
+ IOFactory::load($filename, 'MsDoc');
+ }
+}
diff --git a/tests/PhpWordTests/Reader/ODText/ODTextSectionTest.php b/tests/PhpWordTests/Reader/ODText/ODTextSectionTest.php
new file mode 100644
index 0000000000..8567dbcbea
--- /dev/null
+++ b/tests/PhpWordTests/Reader/ODText/ODTextSectionTest.php
@@ -0,0 +1,84 @@
+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/Reader/ODTextTest.php b/tests/PhpWordTests/Reader/ODTextTest.php
new file mode 100644
index 0000000000..c05705a439
--- /dev/null
+++ b/tests/PhpWordTests/Reader/ODTextTest.php
@@ -0,0 +1,68 @@
+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/PhpWord/Reader/RTFTest.php b/tests/PhpWordTests/Reader/RTFTest.php
similarity index 72%
rename from tests/PhpWord/Reader/RTFTest.php
rename to tests/PhpWordTests/Reader/RTFTest.php
index fed00ceb36..a8f472571b 100644
--- a/tests/PhpWord/Reader/RTFTest.php
+++ b/tests/PhpWordTests/Reader/RTFTest.php
@@ -1,4 +1,5 @@
assertInstanceOf('PhpOffice\\PhpWord\\PhpWord', $phpWord);
+ self::assertInstanceOf('PhpOffice\\PhpWord\\PhpWord', $phpWord);
}
/**
- * Test load exception
- *
- * @expectedException \Exception
- * @expectedExceptionMessage Cannot read
+ * Test load exception.
*/
- public function testLoadException()
+ public function testLoadException(): void
{
+ $this->expectException(Exception::class);
+ $this->expectExceptionMessage('Cannot read');
$filename = __DIR__ . '/../_files/documents/foo.rtf';
IOFactory::load($filename, 'RTF');
}
diff --git a/tests/PhpWordTests/Reader/Word2007/ElementTest.php b/tests/PhpWordTests/Reader/Word2007/ElementTest.php
new file mode 100644
index 0000000000..892e59adf7
--- /dev/null
+++ b/tests/PhpWordTests/Reader/Word2007/ElementTest.php
@@ -0,0 +1,679 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Test node value
+
+
+
+
+
+
+
+
+
+ ';
+
+ $phpWord = $this->getDocumentFromString(['document' => $documentXml]);
+
+ $elements = $phpWord->getSection(0)->getElements();
+ self::assertInstanceOf('PhpOffice\PhpWord\Element\TextRun', $elements[0]);
+ self::assertInstanceOf(Text::class, $elements[0]->getElement(0));
+ $text = $elements[0];
+ self::assertEquals('Test node value', trim($text->getElement(0)->getText()));
+ }
+
+ /**
+ * Test reading of textbreak.
+ */
+ public function testReadTextBreak(): void
+ {
+ $documentXml = '
+
+
+ test string
+
+ ';
+
+ $phpWord = $this->getDocumentFromString(['document' => $documentXml]);
+
+ $elements = $phpWord->getSection(0)->getElements();
+ self::assertInstanceOf('PhpOffice\PhpWord\Element\TextRun', $elements[0]);
+ /** @var \PhpOffice\PhpWord\Element\TextRun $textRun */
+ $textRun = $elements[0];
+ self::assertInstanceOf('PhpOffice\PhpWord\Element\TextBreak', $textRun->getElement(0));
+ self::assertInstanceOf(Text::class, $textRun->getElement(1));
+ self::assertEquals('test string', $textRun->getElement(1)->getText());
+ }
+
+ /**
+ * Test reading content inside w:smartTag.
+ */
+ public function testSmartTag(): void
+ {
+ $documentXml = '
+
+
+ test string
+
+
+ ';
+
+ $phpWord = $this->getDocumentFromString(['document' => $documentXml]);
+
+ $elements = $phpWord->getSection(0)->getElements();
+ self::assertInstanceOf('PhpOffice\PhpWord\Element\TextRun', $elements[0]);
+ /** @var \PhpOffice\PhpWord\Element\TextRun $textRun */
+ $textRun = $elements[0];
+ self::assertInstanceOf(Text::class, $textRun->getElement(0));
+ self::assertEquals('test string', $textRun->getElement(0)->getText());
+ }
+
+ /**
+ * Test reading of textbreak.
+ */
+ public function testReadListItemRunWithFormatting(): void
+ {
+ $documentXml = '
+
+
+
+
+
+
+
+ Two
+
+
+ with
+
+
+
+
+
+ bold
+
+ ';
+
+ $phpWord = $this->getDocumentFromString(['document' => $documentXml]);
+
+ $sections = $phpWord->getSection(0);
+ self::assertNull($sections->getElement(999));
+ self::assertInstanceOf('PhpOffice\PhpWord\Element\ListItemRun', $sections->getElement(0));
+ self::assertEquals(0, $sections->getElement(0)->getDepth());
+
+ $listElements = $sections->getElement(0)->getElements();
+ /** @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());
+ }
+
+ /**
+ * Test reading track changes.
+ */
+ public function testReadTrackChange(): void
+ {
+ $documentXml = '
+
+ One
+
+
+
+ two
+
+
+
+
+ three
+
+
+ ';
+
+ $phpWord = $this->getDocumentFromString(['document' => $documentXml]);
+
+ $elements = $phpWord->getSection(0)->getElements();
+ self::assertInstanceOf('PhpOffice\PhpWord\Element\TextRun', $elements[0]);
+ /** @var \PhpOffice\PhpWord\Element\TextRun $elements */
+ $textRun = $elements[0];
+
+ self::assertEquals('One ', $textRun->getElement(0)->getText());
+
+ self::assertEquals('two', $textRun->getElement(1)->getText());
+ self::assertNotNull($textRun->getElement(1)->getTrackChange());
+ /** @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 TrackChange $trackChange */
+ $trackChange = $textRun->getElement(2)->getTrackChange();
+ self::assertEquals(TrackChange::INSERTED, $trackChange->getChangeType());
+ }
+
+ /**
+ * Test reading of tab.
+ */
+ public function testReadTab(): void
+ {
+ $documentXml = '
+
+ One
+
+ Two
+
+ ';
+
+ $phpWord = $this->getDocumentFromString(['document' => $documentXml]);
+
+ $elements = $phpWord->getSection(0)->getElements();
+ self::assertInstanceOf('PhpOffice\PhpWord\Element\TextRun', $elements[0]);
+ /** @var \PhpOffice\PhpWord\Element\TextRun $textRun */
+ $textRun = $elements[0];
+ self::assertInstanceOf(Text::class, $textRun->getElement(0));
+ self::assertEquals('One', $textRun->getElement(0)->getText());
+ self::assertInstanceOf(Text::class, $textRun->getElement(1));
+ self::assertEquals("\t", $textRun->getElement(1)->getText());
+ self::assertInstanceOf(Text::class, $textRun->getElement(2));
+ self::assertEquals('Two', $textRun->getElement(2)->getText());
+ }
+
+ /**
+ * Test reading Title style.
+ */
+ public function testReadTitleStyle(): void
+ {
+ $documentXml = '
+
+
+
+
+ This is a non formatted title
+
+
+
+
+
+
+
+ This is a
+
+
+
+
+
+ bold
+
+
+ title
+
+ ';
+
+ $stylesXml = '
+
+
+
+
+
+ ';
+
+ $phpWord = $this->getDocumentFromString(['document' => $documentXml, 'styles' => $stylesXml]);
+
+ $elements = $phpWord->getSection(0)->getElements();
+ self::assertInstanceOf('PhpOffice\PhpWord\Element\Title', $elements[0]);
+ /** @var \PhpOffice\PhpWord\Element\Title $title */
+ $title = $elements[0];
+ self::assertEquals('Title', $title->getStyle());
+ self::assertEquals('This is a non formatted title', $title->getText());
+
+ 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::class, $formattedTitle->getText());
+ }
+
+ /**
+ * Test reading of nested table.
+ */
+ public function testReadNestedTable(): void
+ {
+ $documentXml = '
+
+
+
+
+
+
+ ${Field}
+
+
+
+
+
+
+
+ ';
+
+ $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);
+ self::assertInstanceOf('PhpOffice\PhpWord\Element\Table', $nestedTable);
+ }
+
+ /**
+ * Test reading Drawing.
+ */
+ public function testReadDrawing(): void
+ {
+ $documentXml = '
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ';
+
+ $phpWord = $this->getDocumentFromString(['document' => $documentXml]);
+
+ $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());
+ }
+
+ /**
+ * Test reading of ruby.
+ */
+ public function testReadRuby(): void
+ {
+ $documentXml = '
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ わたし
+
+
+
+
+
+
+
+ 私
+
+
+
+
+ ';
+
+ $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\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 = '
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ かみ
+
+
+
+
+
+
+
+ 神
+
+
+
+
+ ';
+
+ $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(); //
+ 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/PhpWord/Reader/Word2007/PartTest.php b/tests/PhpWordTests/Reader/Word2007/PartTest.php
similarity index 73%
rename from tests/PhpWord/Reader/Word2007/PartTest.php
rename to tests/PhpWordTests/Reader/Word2007/PartTest.php
index 6b7d929412..4f19f8b91f 100644
--- a/tests/PhpWord/Reader/Word2007/PartTest.php
+++ b/tests/PhpWordTests/Reader/Word2007/PartTest.php
@@ -1,4 +1,5 @@
@@ -113,55 +114,55 @@ public function testReadFootnote()
';
- $phpWord = $this->getDocumentFromString(array('document' => $documentXml, 'footnotes' => $footnotesXml, 'endnotes' => $endnotesXml));
+ $phpWord = $this->getDocumentFromString(['document' => $documentXml, 'footnotes' => $footnotesXml, 'endnotes' => $endnotesXml]);
$elements = $phpWord->getSection(0)->getElements();
- $this->assertInstanceOf('PhpOffice\PhpWord\Element\TextRun', $elements[0]);
+ self::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());
+ self::assertInstanceOf('PhpOffice\PhpWord\Element\Text', $text);
+ self::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());
+ self::assertInstanceOf('PhpOffice\PhpWord\Element\Footnote', $documentFootnote);
+ self::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());
+ self::assertInstanceOf('PhpOffice\PhpWord\Element\Footnote', $footnote);
+ self::assertInstanceOf('PhpOffice\PhpWord\Element\Text', $footnote->getElement(0));
+ self::assertEquals('footnote text', $footnote->getElement(0)->getText());
+ self::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());
+ self::assertInstanceOf('PhpOffice\PhpWord\Element\Text', $text);
+ self::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());
+ self::assertInstanceOf('PhpOffice\PhpWord\Element\Endnote', $documentEndnote);
+ self::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());
+ self::assertInstanceOf('PhpOffice\PhpWord\Element\Endnote', $endnote);
+ self::assertEquals(2, $endnote->getRelationId());
+ self::assertInstanceOf('PhpOffice\PhpWord\Element\Text', $endnote->getElement(0));
+ self::assertEquals('This is an endnote', $endnote->getElement(0)->getText());
}
- public function testReadHeadingWithOverriddenStyle()
+ public function testReadHeadingWithOverriddenStyle(): void
{
$documentXml = '
@@ -208,28 +209,28 @@ public function testReadHeadingWithOverriddenStyle()
';
- $phpWord = $this->getDocumentFromString(array('document' => $documentXml, 'styles' => $stylesXml));
+ $phpWord = $this->getDocumentFromString(['document' => $documentXml, 'styles' => $stylesXml]);
$elements = $phpWord->getSection(0)->getElements();
- $this->assertInstanceOf('PhpOffice\PhpWord\Element\Title', $elements[0]);
+ self::assertInstanceOf('PhpOffice\PhpWord\Element\Title', $elements[0]);
/** @var \PhpOffice\PhpWord\Element\Title $title */
$title = $elements[0];
- $this->assertEquals('Heading1', $title->getStyle());
+ self::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());
+ self::assertInstanceOf('PhpOffice\PhpWord\Element\Text', $text);
+ self::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());
+ self::assertInstanceOf('PhpOffice\PhpWord\Element\Text', $text);
+ self::assertEquals('heading', $text->getText());
+ self::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());
+ self::assertInstanceOf('PhpOffice\PhpWord\Element\Text', $text);
+ self::assertEquals(' but with parts not in bold', $text->getText());
}
}
diff --git a/tests/PhpWordTests/Reader/Word2007/StyleTest.php b/tests/PhpWordTests/Reader/Word2007/StyleTest.php
new file mode 100644
index 0000000000..7f4afde476
--- /dev/null
+++ b/tests/PhpWordTests/Reader/Word2007/StyleTest.php
@@ -0,0 +1,417 @@
+
+
+
+
+ ';
+
+ $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());
+ self::assertEquals(Table::LAYOUT_FIXED, $elements[0]->getStyle()->getLayout());
+ }
+
+ /**
+ * Test reading of table position.
+ */
+ public function testReadTablePosition(): 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());
+ self::assertNotNull($elements[0]->getStyle()->getPosition());
+ self::assertInstanceOf('PhpOffice\PhpWord\Style\TablePosition', $elements[0]->getStyle()->getPosition());
+ /** @var TablePosition $tableStyle */
+ $tableStyle = $elements[0]->getStyle()->getPosition();
+ self::assertEquals(10, $tableStyle->getLeftFromText());
+ self::assertEquals(20, $tableStyle->getRightFromText());
+ self::assertEquals(30, $tableStyle->getTopFromText());
+ self::assertEquals(40, $tableStyle->getBottomFromText());
+ self::assertEquals(TablePosition::VANCHOR_PAGE, $tableStyle->getVertAnchor());
+ self::assertEquals(TablePosition::HANCHOR_MARGIN, $tableStyle->getHorzAnchor());
+ self::assertEquals(TablePosition::XALIGN_CENTER, $tableStyle->getTblpXSpec());
+ self::assertEquals(50, $tableStyle->getTblpX());
+ self::assertEquals(TablePosition::YALIGN_TOP, $tableStyle->getTblpYSpec());
+ 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 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());
+ }
+
+ public function testReadTableCellsWithVerticalMerge(): void
+ {
+ $documentXml = '
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ';
+
+ $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.
+ */
+ public function testReadPosition(): void
+ {
+ $documentXml = '
+
+
+
+
+ This text is lowered
+
+ ';
+
+ $phpWord = $this->getDocumentFromString(['document' => $documentXml]);
+
+ $elements = $phpWord->getSection(0)->getElements();
+ /** @var TextRun $elements */
+ $textRun = $elements[0];
+ 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 Style\Font $fontStyle */
+ $fontStyle = $textRun->getElement(0)->getFontStyle();
+ self::assertEquals(15, $fontStyle->getPosition());
+ }
+
+ public function testReadIndent(): 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 Table $tableStyle */
+ $tableStyle = $elements[0]->getStyle();
+ self::assertSame(TblWidth::TWIP, $tableStyle->getIndent()->getType());
+ self::assertSame(2160, $tableStyle->getIndent()->getValue());
+ }
+
+ public function testReadTableRTL(): 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 Table $tableStyle */
+ $tableStyle = $elements[0]->getStyle();
+ self::assertTrue($tableStyle->isBidiVisual());
+ }
+
+ public function testReadHidden(): void
+ {
+ $documentXml = '
+
+
+
+
+ This text is hidden
+
+ ';
+
+ $phpWord = $this->getDocumentFromString(['document' => $documentXml]);
+
+ $elements = $phpWord->getSection(0)->getElements();
+ /** @var TextRun $elements */
+ $textRun = $elements[0];
+ 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 Style\Font $fontStyle */
+ $fontStyle = $textRun->getElement(0)->getFontStyle();
+ self::assertTrue($fontStyle->isHidden());
+ }
+
+ public function testReadHeading(): void
+ {
+ Style::resetStyles();
+
+ $documentXml = '
+
+
+
+
+
+
+
+
+
+
+
+
+ ';
+
+ $name = 'Heading_1';
+
+ $this->getDocumentFromString(['styles' => $documentXml]);
+ self::assertInstanceOf('PhpOffice\\PhpWord\\Style\\Font', Style::getStyle($name));
+ }
+
+ public function testPageVerticalAlign(): void
+ {
+ $documentXml = '
+
+ ';
+
+ $phpWord = $this->getDocumentFromString(['document' => $documentXml]);
+
+ $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,
+ int $firstLineChars
+ ): void {
+ $documentXml = "
+
+ $indent
+
+
+ 1.
+
+ ";
+
+ $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());
+ self::assertSame($firstLineChars, $indentation->getFirstLineChars());
+ }
+
+ /**
+ * @return Generator
+ */
+ public static function providerIndentation()
+ {
+ yield [
+ ' ',
+ 709.00,
+ 488.00,
+ 10.0,
+ 490.00,
+ 140,
+ ];
+ yield [
+ ' ',
+ 709.00,
+ 488.00,
+ 10.0,
+ 490.00,
+ 0,
+ ];
+ yield [
+ ' ',
+ 0,
+ 0,
+ 10.0,
+ 490.00,
+ 0,
+ ];
+ yield [
+ ' ',
+ 709.00,
+ 0,
+ 0,
+ 0,
+ 0,
+ ];
+ yield [
+ ' ',
+ 0,
+ 488.00,
+ 0,
+ 0,
+ 0,
+ ];
+ }
+}
diff --git a/tests/PhpWordTests/Reader/Word2007Test.php b/tests/PhpWordTests/Reader/Word2007Test.php
new file mode 100644
index 0000000000..65c8a4a71b
--- /dev/null
+++ b/tests/PhpWordTests/Reader/Word2007Test.php
@@ -0,0 +1,264 @@
+canRead(dirname(__DIR__, 1) . '/_files/documents/reader.docx'));
+ }
+
+ /**
+ * Can read exception.
+ */
+ public function testCanReadFailed(): void
+ {
+ $object = new Word2007();
+ self::assertFalse($object->canRead(dirname(__DIR__, 1) . '/_files/documents/foo.docx'));
+ }
+
+ /**
+ * Load.
+ */
+ public function testLoad(): void
+ {
+ $phpWord = IOFactory::load(dirname(__DIR__, 1) . '/_files/documents/reader.docx', 'Word2007');
+
+ self::assertInstanceOf(PhpWord::class, $phpWord);
+ self::assertTrue($phpWord->getSettings()->hasDoNotTrackMoves());
+ self::assertFalse($phpWord->getSettings()->hasDoNotTrackFormatting());
+ self::assertEquals(100, $phpWord->getSettings()->getZoom());
+
+ $doc = TestHelperDOCX::getDocument($phpWord);
+ 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);
+
+ $element2e31 = $section2->getElement(31);
+ self::assertInstanceOf(TextRun::class, $element2e31);
+ self::assertEquals('This is a paragraph with border differents', $element2e31->getText());
+
+ /** @var Paragraph $element2e31pStyle */
+ $element2e31pStyle = $element2e31->getParagraphStyle();
+ self::assertInstanceOf(Paragraph::class, $element2e31pStyle);
+
+ // Top
+ self::assertEquals('FFFF00', $element2e31pStyle->getBorderTopColor());
+ self::assertEquals('10', $element2e31pStyle->getBorderTopSize());
+ self::assertEquals('dotted', $element2e31pStyle->getBorderTopStyle());
+ // Right
+ self::assertEquals('00A933', $element2e31pStyle->getBorderRightColor());
+ self::assertEquals('4', $element2e31pStyle->getBorderRightSize());
+ self::assertEquals('dashed', $element2e31pStyle->getBorderRightStyle());
+ // Bottom
+ self::assertEquals('F10D0C', $element2e31pStyle->getBorderBottomColor());
+ self::assertEquals('8', $element2e31pStyle->getBorderBottomSize());
+ self::assertEquals('dashSmallGap', $element2e31pStyle->getBorderBottomStyle());
+ // Left
+ self::assertEquals('3465A4', $element2e31pStyle->getBorderLeftColor());
+ self::assertEquals('8', $element2e31pStyle->getBorderLeftSize());
+ self::assertEquals('dashed', $element2e31pStyle->getBorderLeftStyle());
+ }
+
+ /**
+ * Load a Word 2011 file.
+ */
+ public function testLoadWord2011(): void
+ {
+ $reader = new Word2007();
+ $phpWord = $reader->load(dirname(__DIR__, 1) . '/_files/documents/reader-2011.docx');
+
+ 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 static function providerSettingsImageLoading(): iterable
+ {
+ return [
+ [true],
+ [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());
+ }
+
+ 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/SettingsTest.php b/tests/PhpWordTests/SettingsTest.php
new file mode 100644
index 0000000000..f8b9af661d
--- /dev/null
+++ b/tests/PhpWordTests/SettingsTest.php
@@ -0,0 +1,332 @@
+compatibility = Settings::hasCompatibility();
+ $this->defaultFontColor = Settings::getDefaultFontColor();
+ $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->pdfRendererOptions = Settings::getPdfRendererOptions();
+ $this->pdfRendererPath = Settings::getPdfRendererPath();
+ $this->tempDir = Settings::getTempDir();
+ $this->zipClass = Settings::getZipClass();
+ $this->defaultRtl = Settings::isDefaultRtl();
+ }
+
+ protected function tearDown(): void
+ {
+ Settings::setCompatibility($this->compatibility);
+ Settings::setDefaultFontColor($this->defaultFontColor);
+ 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::setPdfRendererOptions($this->pdfRendererOptions);
+ Settings::setPdfRendererPath($this->pdfRendererPath);
+ Settings::setTempDir($this->tempDir);
+ Settings::setZipClass($this->zipClass);
+ Settings::setDefaultRtl($this->defaultRtl);
+ }
+
+ /**
+ * Test set/get compatibity option.
+ */
+ public function testSetGetCompatibility(): void
+ {
+ self::assertTrue(Settings::hasCompatibility());
+ self::assertTrue(Settings::setCompatibility(false));
+ self::assertFalse(Settings::hasCompatibility());
+ }
+
+ /**
+ * Test set/get outputEscapingEnabled option.
+ */
+ public function testSetGetOutputEscapingEnabled(): void
+ {
+ self::assertFalse(Settings::isOutputEscapingEnabled());
+ Settings::setOutputEscapingEnabled(true);
+ 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.
+ */
+ public function testSetGetZipClass(): void
+ {
+ self::assertEquals(Settings::ZIPARCHIVE, Settings::getZipClass());
+ self::assertFalse(Settings::setZipClass('foo'));
+ self::assertEquals(Settings::ZIPARCHIVE, Settings::getZipClass());
+ self::assertTrue(Settings::setZipClass(Settings::PCLZIP));
+ self::assertEquals(Settings::getZipClass(), Settings::PCLZIP);
+ self::assertFalse(Settings::setZipClass('foo'));
+ self::assertEquals(Settings::getZipClass(), Settings::PCLZIP);
+ }
+
+ /**
+ * Test set/get PDF renderer.
+ */
+ public function testSetGetPdfRenderer(): void
+ {
+ $domPdfPath = realpath(PHPWORD_TESTS_BASE_DIR . '/../vendor/dompdf/dompdf');
+
+ self::assertFalse(Settings::setPdfRenderer('FOO', 'dummy/path'));
+ self::assertTrue(Settings::setPdfRenderer(Settings::PDF_RENDERER_DOMPDF, $domPdfPath));
+ self::assertEquals(Settings::PDF_RENDERER_DOMPDF, Settings::getPdfRendererName());
+ self::assertEquals($domPdfPath, Settings::getPdfRendererPath());
+ self::assertFalse(Settings::setPdfRendererPath('dummy/path'));
+ 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.
+ */
+ public function testSetGetMeasurementUnit(): void
+ {
+ self::assertEquals(Settings::UNIT_TWIP, Settings::getMeasurementUnit());
+ self::assertFalse(Settings::setMeasurementUnit('foo'));
+ self::assertEquals(Settings::UNIT_TWIP, Settings::getMeasurementUnit());
+ self::assertTrue(Settings::setMeasurementUnit(Settings::UNIT_INCH));
+ self::assertEquals(Settings::UNIT_INCH, Settings::getMeasurementUnit());
+ self::assertFalse(Settings::setMeasurementUnit('foo'));
+ self::assertEquals(Settings::UNIT_INCH, Settings::getMeasurementUnit());
+ }
+
+ /**
+ * @covers ::getTempDir
+ */
+ public function testPhpTempDirIsUsedByDefault(): void
+ {
+ self::assertEquals(sys_get_temp_dir(), Settings::getTempDir());
+ }
+
+ /**
+ * @covers ::getTempDir
+ * @covers ::setTempDir
+ *
+ * @depends testPhpTempDirIsUsedByDefault
+ */
+ public function testTempDirCanBeSet(): void
+ {
+ $userDefinedTempDir = 'C:\PhpWordTemp';
+ Settings::setTempDir($userDefinedTempDir);
+ $currentTempDir = Settings::getTempDir();
+ self::assertEquals($userDefinedTempDir, $currentTempDir);
+ self::assertNotEquals(sys_get_temp_dir(), $currentTempDir);
+ }
+
+ /**
+ * Test set/get default font name.
+ */
+ public function testSetGetDefaultFontName(): void
+ {
+ self::assertEquals(Settings::DEFAULT_FONT_NAME, Settings::getDefaultFontName());
+ self::assertFalse(Settings::setDefaultFontName(' '));
+ self::assertEquals(Settings::DEFAULT_FONT_NAME, Settings::getDefaultFontName());
+ self::assertTrue(Settings::setDefaultFontName('Times New Roman'));
+ self::assertEquals('Times New Roman', Settings::getDefaultFontName());
+ self::assertFalse(Settings::setDefaultFontName(' '));
+ 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.
+ */
+ public function testSetGetDefaultFontSize(): void
+ {
+ self::assertEquals(Settings::DEFAULT_FONT_SIZE, Settings::getDefaultFontSize());
+ self::assertFalse(Settings::setDefaultFontSize(null));
+ self::assertEquals(Settings::DEFAULT_FONT_SIZE, Settings::getDefaultFontSize());
+ self::assertTrue(Settings::setDefaultFontSize(12));
+ 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());
+ }
+
+ /**
+ * 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.
+ */
+ public function testSetGetDefaultPaper(): void
+ {
+ $dflt = Settings::DEFAULT_PAPER;
+ $chng = 'A4';
+ $doc = new PhpWord();
+ self::assertEquals($dflt, Settings::getDefaultPaper());
+ $sec1 = $doc->addSection();
+ self::assertEquals($dflt, $sec1->getStyle()->getPaperSize());
+ self::assertFalse(Settings::setDefaultPaper(''));
+ self::assertEquals($dflt, Settings::getDefaultPaper());
+ self::assertTrue(Settings::setDefaultPaper($chng));
+ self::assertEquals($chng, Settings::getDefaultPaper());
+ $sec2 = $doc->addSection();
+ self::assertEquals($chng, $sec2->getStyle()->getPaperSize());
+ $sec3 = $doc->addSection(['paperSize' => 'Legal']);
+ self::assertEquals('Legal', $sec3->getStyle()->getPaperSize());
+ self::assertFalse(Settings::setDefaultPaper(''));
+ self::assertEquals($chng, Settings::getDefaultPaper());
+ }
+
+ /**
+ * Test load config.
+ */
+ public function testLoadConfig(): void
+ {
+ $expected = [
+ 'compatibility' => true,
+ 'zipClass' => 'ZipArchive',
+ 'pdfRendererName' => 'DomPDF',
+ 'pdfRendererPath' => '',
+ 'defaultFontName' => 'Arial',
+ 'defaultFontSize' => 10,
+ 'defaultFontColor' => '000000',
+ 'outputEscapingEnabled' => false,
+ 'defaultPaper' => 'A4',
+ ];
+
+ // Test default value
+ self::assertEquals($expected, Settings::loadConfig());
+
+ // Test with valid file
+ self::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);
+ }
+ self::assertEquals(Settings::$meth(), $value);
+ }
+
+ // Test with invalid file
+ self::assertEmpty(Settings::loadConfig(__DIR__ . '/../../phpunit.xml.dist'));
+ }
+}
diff --git a/tests/PhpWordTests/Shared/ConverterTest.php b/tests/PhpWordTests/Shared/ConverterTest.php
new file mode 100644
index 0000000000..36ba797aeb
--- /dev/null
+++ b/tests/PhpWordTests/Shared/ConverterTest.php
@@ -0,0 +1,141 @@
+process();
+
+ self::assertEquals([], $css->getStyles());
+ }
+
+ public function testBasicCss(): void
+ {
+ $cssContent = '.pStyle {
+ font-size:15px;
+ }';
+
+ $css = new Css($cssContent);
+ $css->process();
+
+ self::assertEquals([
+ '.pStyle' => [
+ 'font-size' => '15px',
+ ],
+ ], $css->getStyles());
+ self::assertEquals([
+ 'font-size' => '15px',
+ ], $css->getStyle('.pStyle'));
+ }
+}
diff --git a/tests/PhpWordTests/Shared/DrawingTest.php b/tests/PhpWordTests/Shared/DrawingTest.php
new file mode 100644
index 0000000000..dbaa42a686
--- /dev/null
+++ b/tests/PhpWordTests/Shared/DrawingTest.php
@@ -0,0 +1,115 @@
+addSection();
- $this->assertCount(0, $section->getElements());
+ self::assertCount(0, $section->getElements());
// Heading
- $styles = array('strong', 'em', 'sup', 'sub');
- for ($level = 1; $level <= 6; $level++) {
+ $styles = ['strong', 'em', 'sup', 'sub'];
+ for ($level = 1; $level <= 6; ++$level) {
$content .= "Heading {$level} ";
}
@@ -58,7 +78,7 @@ public function testAddHtml()
// Add HTML
Html::addHtml($section, $content);
- $this->assertCount(7, $section->getElements());
+ self::assertCount(7, $section->getElements());
// Other parts
$section = $phpWord->addSection();
@@ -76,127 +96,312 @@ public function testAddHtml()
}
/**
- * Test that html already in body element can be read
+ * Test that html already in body element can be read.
+ *
* @ignore
*/
- public function testParseFullHtml()
+ public function testParseFullHtml(): void
{
$section = new Section(1);
Html::addHtml($section, 'test paragraph1
test paragraph2
', true);
- $this->assertCount(2, $section->getElements());
+ self::assertCount(2, $section->getElements());
+ }
+
+ public function testParseHeader(): void
+ {
+ $phpWord = new PhpWord();
+ $section = $phpWord->addSection();
+ Html::addHtml($section, 'Text ');
+
+ 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, 'Text ');
+
+ 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
+ * Test HTML entities.
*/
- public function testParseHtmlEntities()
+ public function testParseHtmlEntities(): void
{
\PhpOffice\PhpWord\Settings::setOutputEscapingEnabled(true);
- $phpWord = new \PhpOffice\PhpWord\PhpWord();
+ $phpWord = new 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);
+ self::assertTrue($doc->elementExists('/w:document/w:body/w:p[1]/w:r/w:t'));
+ self::assertEquals('text with entities ', $doc->getElement('/w:document/w:body/w:p[1]/w:r/w:t')->nodeValue);
+ }
+
+ public function testParseStyle(): void
+ {
+ $html = '
+
+ 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'));
+ }
+
+ public function testParseStyleTableClassName(): void
+ {
+ $html = '';
+ $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 text-decoration style.
+ */
+ public function testParseTextDecoration(): 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:u'));
+ self::assertEquals('single', $doc->getElementAttribute('/w:document/w:body/w:p/w:r/w:rPr/w:u', 'w:val'));
}
/**
- * Test underline
+ * Test underline.
*/
- public function testParseUnderline()
+ public function testParseUnderline(): void
{
$html = 'test ';
- $phpWord = new \PhpOffice\PhpWord\PhpWord();
+ $phpWord = new 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'));
+ self::assertTrue($doc->elementExists('/w:document/w:body/w:p/w:r/w:rPr/w:u'));
+ self::assertEquals('single', $doc->getElementAttribute('/w:document/w:body/w:p/w:r/w:rPr/w:u', 'w:val'));
}
/**
- * Test text-decoration style
+ * Test width.
+ *
+ * @dataProvider providerParseWidth
*/
- public function testParseTextDecoration()
+ public function testParseWidth(string $htmlSize, float $docxSize, string $docxUnit): void
{
- $html = 'test ';
- $phpWord = new \PhpOffice\PhpWord\PhpWord();
+ $html = '';
+ $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.
+ */
+ public function testParseFontVariant(): void
+ {
+ $html = 'test ';
+ $phpWord = new 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'));
+ 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
+ * Test font.
*/
- public function testParseFont()
+ public function testParseFont(): void
{
$html = 'test ';
- $phpWord = new \PhpOffice\PhpWord\PhpWord();
+ $phpWord = new 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'));
+ self::assertTrue($doc->elementExists('/w:document/w:body/w:p/w:r/w:rPr'));
//TODO check style
}
/**
- * Test line-height style
+ * Test line-height style.
*/
- public function testParseLineHeight()
+ public function testParseLineHeight(): void
{
- $phpWord = new \PhpOffice\PhpWord\PhpWord();
+ $phpWord = new PhpWord();
$section = $phpWord->addSection();
Html::addHtml($section, 'test
');
Html::addHtml($section, 'test
');
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'));
- $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'));
+ self::assertTrue($doc->elementExists('/w:document/w:body/w:p[1]/w:pPr/w:spacing'));
+ self::assertEquals(Paragraph::LINE_HEIGHT * 1.5, $doc->getElementAttribute('/w:document/w:body/w:p[1]/w:pPr/w:spacing', 'w:line'));
+ self::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'));
+ self::assertTrue($doc->elementExists('/w:document/w:body/w:p[2]/w:pPr/w:spacing'));
+ self::assertEquals(300, $doc->getElementAttribute('/w:document/w:body/w:p[2]/w:pPr/w:spacing', 'w:line'));
+ self::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'));
+ self::assertTrue($doc->elementExists('/w:document/w:body/w:p[3]/w:pPr/w:spacing'));
+ self::assertEquals(Paragraph::LINE_HEIGHT * 1.2, $doc->getElementAttribute('/w:document/w:body/w:p[3]/w:pPr/w:spacing', 'w:line'));
+ self::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'));
+ self::assertTrue($doc->elementExists('/w:document/w:body/w:p[4]/w:pPr/w:spacing'));
+ self::assertEquals(244.8, $doc->getElementAttribute('/w:document/w:body/w:p[4]/w:pPr/w:spacing', 'w:line'));
+ self::assertEquals(LineSpacingRule::EXACT, $doc->getElementAttribute('/w:document/w:body/w:p[4]/w:pPr/w:spacing', 'w:lineRule'));
+
+ 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
+ {
+ $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 = '
+
+
+ full
+ mix
+ top
+ bottom
+ left
+
+
+
';
+ 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
+ * Test text-indent style.
*/
- public function testParseTextIndent()
+ public function testParseTextIndent(): void
{
- $phpWord = new \PhpOffice\PhpWord\PhpWord();
+ $phpWord = new 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'));
+ self::assertTrue($doc->elementExists('/w:document/w:body/w:p/w:pPr/w:ind'));
+ self::assertEquals(750, $doc->getElementAttribute('/w:document/w:body/w:p/w:pPr/w:ind', 'w:firstLine'));
}
/**
- * Test text-align style
+ * Test text-align style.
*/
- public function testParseTextAlign()
+ public function testParseTextAlign(): void
{
- $phpWord = new \PhpOffice\PhpWord\PhpWord();
+ $phpWord = new PhpWord();
$section = $phpWord->addSection();
Html::addHtml($section, 'test
');
Html::addHtml($section, 'test
');
@@ -204,100 +409,114 @@ public function testParseTextAlign()
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(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'));
+ self::assertTrue($doc->elementExists('/w:document/w:body/w:p/w:pPr/w:jc'));
+ self::assertEquals(Jc::START, $doc->getElementAttribute('/w:document/w:body/w:p[1]/w:pPr/w:jc', 'w:val'));
+ self::assertEquals(Jc::END, $doc->getElementAttribute('/w:document/w:body/w:p[2]/w:pPr/w:jc', 'w:val'));
+ self::assertEquals(Jc::CENTER, $doc->getElementAttribute('/w:document/w:body/w:p[3]/w:pPr/w:jc', 'w:val'));
+ self::assertEquals(Jc::BOTH, $doc->getElementAttribute('/w:document/w:body/w:p[4]/w:pPr/w:jc', 'w:val'));
}
/**
- * Test font-size style
+ * Test font-size style.
*/
- public function testParseFontSize()
+ public function testParseFontSize(): void
{
- $phpWord = new \PhpOffice\PhpWord\PhpWord();
+ $phpWord = new 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'));
+ self::assertTrue($doc->elementExists('/w:document/w:body/w:p/w:r/w:rPr/w:sz'));
+ self::assertEquals('20', $doc->getElementAttribute('/w:document/w:body/w:p[1]/w:r/w:rPr/w:sz', 'w:val'));
+ self::assertEquals('15', $doc->getElementAttribute('/w:document/w:body/w:p[2]/w:r/w:rPr/w:sz', 'w:val'));
}
/**
- * Test direction style
+ * Test direction style.
*/
- public function testParseTextDirection()
+ public function testParseTextDirection(): void
{
- $phpWord = new \PhpOffice\PhpWord\PhpWord();
+ $phpWord = new 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'));
+ self::assertTrue($doc->elementExists('/w:document/w:body/w:p/w:r/w:rPr/w:rtl'));
}
/**
- * Test html lang
+ * Test html lang.
*/
- public function testParseLang()
+ public function testParseLang(): void
{
- $phpWord = new \PhpOffice\PhpWord\PhpWord();
+ $phpWord = new 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'));
+ self::assertTrue($doc->elementExists('/w:document/w:body/w:p/w:r/w:rPr/w:lang'));
+ self::assertEquals('fr-BE', $doc->getElementAttribute('/w:document/w:body/w:p/w:r/w:rPr/w:lang', 'w:val'));
}
/**
- * Test font-family style
+ * Test font-family style.
*/
- public function testParseFontFamily()
+ public function testParseFontFamily(): void
{
- $phpWord = new \PhpOffice\PhpWord\PhpWord();
+ $phpWord = new 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'));
+ self::assertTrue($doc->elementExists('/w:document/w:body/w:p/w:r/w:rPr/w:rFonts'));
+ self::assertEquals('Arial', $doc->getElementAttribute('/w:document/w:body/w:p[1]/w:r/w:rPr/w:rFonts', 'w:ascii'));
+ self::assertEquals('Times New Roman', $doc->getElementAttribute('/w:document/w:body/w:p[2]/w:r/w:rPr/w:rFonts', 'w:ascii'));
}
/**
- * Test parsing paragraph and span styles
+ * Test parsing paragraph and span styles.
*/
- public function testParseParagraphAndSpanStyle()
+ public function testParseParagraphAndSpanStyle(): void
{
- $phpWord = new \PhpOffice\PhpWord\PhpWord();
+ $phpWord = new 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->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'));
+ self::assertTrue($doc->elementExists('/w:document/w:body/w:p/w:pPr/w:jc'));
+ self::assertTrue($doc->elementExists('/w:document/w:body/w:p/w:pPr/w:spacing'));
+ self::assertEquals(Jc::CENTER, $doc->getElementAttribute('/w:document/w:body/w:p[1]/w:pPr/w:jc', 'w:val'));
+ self::assertEquals('single', $doc->getElementAttribute('/w:document/w:body/w:p[1]/w:r/w:rPr/w:u', 'w:val'));
}
/**
- * Test parsing table
+ * Test parsing paragraph with `page-break-after` style.
*/
- public function testParseTable()
+ public function testParseParagraphWithPageBreak(): void
{
- $phpWord = new \PhpOffice\PhpWord\PhpWord();
+ $phpWord = new PhpWord();
$section = $phpWord->addSection();
- $html = '
+ Html::addHtml($section, '
');
+
+ $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007');
+ self::assertTrue($doc->elementExists('/w:document/w:body/w:p/w:r/w:br'));
+ self::assertEquals('page', $doc->getElementAttribute('/w:document/w:body/w:p/w:r/w:br', 'w:type'));
+ }
+
+ /**
+ * Test parsing table.
+ */
+ public function testParseTable(): void
+ {
+ $phpWord = new PhpWord();
+ $section = $phpWord->addSection();
+ $html = '
-
- header a
- header b
+
+ header a
+ header b
header c
@@ -309,29 +528,255 @@ public function testParseTable()
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: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'));
+ self::assertTrue($doc->elementExists('/w:document/w:body/w:tbl'));
+ self::assertTrue($doc->elementExists('/w:document/w:body/w:tbl/w:tr/w:tc'));
+ self::assertTrue($doc->elementExists('/w:document/w:body/w:tbl/w:tblPr/w:jc'));
+ self::assertEquals(Jc::START, $doc->getElementAttribute('/w:document/w:body/w:tbl/w:tblPr/w:jc', 'w:val'));
//check border colors
- $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'));
+ self::assertEquals('00EE00', $doc->getElementAttribute('/w:document/w:body/w:tbl/w:tr[1]/w:tc[2]/w:tcPr/w:tcBorders/w:top', 'w:color'));
+ self::assertEquals('00EE00', $doc->getElementAttribute('/w:document/w:body/w:tbl/w:tr[1]/w:tc[2]/w:tcPr/w:tcBorders/w:right', 'w:color'));
+ self::assertEquals('00EE00', $doc->getElementAttribute('/w:document/w:body/w:tbl/w:tr[1]/w:tc[2]/w:tcPr/w:tcBorders/w:bottom', 'w:color'));
+ self::assertEquals('00EE00', $doc->getElementAttribute('/w:document/w:body/w:tbl/w:tr[1]/w:tc[2]/w:tcPr/w:tcBorders/w:left', 'w:color'));
+
+ self::assertEquals('00AA00', $doc->getElementAttribute('/w:document/w:body/w:tbl/w:tr[1]/w:tc[3]/w:tcPr/w:tcBorders/w:top', 'w:color'));
+ self::assertEquals('00BB00', $doc->getElementAttribute('/w:document/w:body/w:tbl/w:tr[1]/w:tc[3]/w:tcPr/w:tcBorders/w:right', 'w:color'));
+ self::assertEquals('00CC00', $doc->getElementAttribute('/w:document/w:body/w:tbl/w:tr[1]/w:tc[3]/w:tcPr/w:tcBorders/w:bottom', 'w:color'));
+ self::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
+ self::assertTrue($doc->elementExists('/w:document/w:body/w:tbl/w:tr[1]/w:tc[1]/w:p'));
+ self::assertFalse($doc->elementExists('/w:document/w:body/w:tbl/w:tr[1]/w:tc[1]/w:p/w:pPr/w:pBdr'));
+ self::assertTrue($doc->elementExists('/w:document/w:body/w:tbl/w:tr[1]/w:tc[2]/w:p'));
+ self::assertFalse($doc->elementExists('/w:document/w:body/w:tbl/w:tr[1]/w:tc[2]/w:p/w:pPr/w:pBdr'));
+ }
+
+ /**
+ * Parse widths in tables and cells, which also allows for controlling column width.
+ */
+ public function testParseTableAndCellWidth(): void
+ {
+ $phpWord = new 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.C1
+ 50pt
+ T2.R2.C3
+
+
+ 300px
+ T2.R3.C3
+
+
+
+
+
+HTML;
+
+ Html::addHtml($section, $html);
+ $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007');
- $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'));
+ // outer table grid
+ $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(TblWidth::TWIP, $doc->getElement($xpath)->getAttribute('w:type'));
+
+ // elementExists($xpath));
+ self::assertEquals(6000, $doc->getElement($xpath)->getAttribute('w:w'));
+ self::assertEquals(TblWidth::TWIP, $doc->getElement($xpath)->getAttribute('w:type'));
+
+ // elementExists($xpath));
+ self::assertEquals(4500, $doc->getElement($xpath)->getAttribute('w:w'));
+ self::assertEquals(TblWidth::TWIP, $doc->getElement($xpath)->getAttribute('w:type'));
}
/**
- * Tests parsing of ul/li
+ * Parse heights in rows, which also allows for controlling column height.
*/
- public function testParseList()
+ public function testParseTableRowHeight(): void
{
- $phpWord = new \PhpOffice\PhpWord\PhpWord();
+ $phpWord = new PhpWord();
+ $section = $phpWord->addSection([
+ 'orientation' => \PhpOffice\PhpWord\Style\Section::ORIENTATION_LANDSCAPE,
+ ]);
+
+ $html = <<
+
+ 100px
+
+
+ 200pt
+
+
+
+
+
+
+
+HTML;
+
+ Html::addHtml($section, $html);
+ $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007');
+
+ // elementExists($xpath));
+ self::assertEquals(4000, $doc->getElement($xpath)->getAttribute('w:val'));
+ self::assertEquals('exact', $doc->getElement($xpath)->getAttribute('w:hRule'));
+
+ //
+
+
+ Header
+
+
+
+ Cell 1
+ Cell 2
+
+
';
+ Html::addHtml($section, $html);
+
+ $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007');
+ self::assertTrue($doc->elementExists('/w:document/w:body/w:tbl'));
+ self::assertTrue($doc->elementExists('/w:document/w:body/w:tbl/w:tblPr'));
+ self::assertTrue($doc->elementExists('/w:document/w:body/w:tbl/w:tblPr/w:tblBorders'));
+ self::assertTrue($doc->elementExists('/w:document/w:body/w:tbl/w:tblPr/w:tblBorders/w:top'));
+ // 10 pixels = 150 twips
+ self::assertEquals(150, $doc->getElementAttribute('/w:document/w:body/w:tbl/w:tblPr/w:tblBorders/w:top', 'w:sz'));
+ }
+
+ /**
+ * Test parsing background color for table rows and table cellspacing.
+ */
+ public function testParseTableCellspacingRowBgColor(): void
+ {
+ $phpWord = new PhpWord();
+ $section = $phpWord->addSection([
+ 'orientation' => \PhpOffice\PhpWord\Style\Section::ORIENTATION_LANDSCAPE,
+ ]);
+
+ // borders & backgrounds are here just for better visual comparison
+ $html = <<
+
+ A
+ B
+
+
+ C
+ D
+
+
+HTML;
+
+ Html::addHtml($section, $html);
+ $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007');
+
+ $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(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));
+ self::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';
+ self::assertTrue($doc->elementExists($xpath));
+ self::assertEquals('FF0000', $doc->getElement($xpath)->getAttribute('w:fill'));
+ }
+
+ /**
+ * Test parsing background color for table rows and table cellspacing.
+ */
+ public function testParseTableStyleAttributeInlineStyle(): void
+ {
+ $phpWord = new PhpWord();
+ $section = $phpWord->addSection([
+ 'orientation' => \PhpOffice\PhpWord\Style\Section::ORIENTATION_LANDSCAPE,
+ ]);
+
+ $html = '';
+
+ 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(100 * 50, $doc->getElement($xpath)->getAttribute('w:w'));
+ 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));
+ self::assertEquals('red', $doc->getElement($xpath)->getAttribute('w:fill'));
+ }
+
+ /**
+ * Tests parsing of ul/li.
+ */
+ public function testParseList(): void
+ {
+ $phpWord = new PhpWord();
$section = $phpWord->addSection();
$html = '
@@ -348,19 +793,19 @@ public function testParseList()
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);
- $this->assertTrue($doc->elementExists('/w:document/w:body/w:p/w:r/w:rPr/w:b'));
+ self::assertTrue($doc->elementExists('/w:document/w:body/w:p/w:pPr/w:numPr/w:numId'));
+ self::assertTrue($doc->elementExists('/w:document/w:body/w:p/w:r/w:t'));
+ self::assertEquals('list item1', $doc->getElement('/w:document/w:body/w:p[1]/w:r/w:t')->nodeValue);
+ self::assertEquals('list item2', $doc->getElement('/w:document/w:body/w:p[2]/w:r/w:t')->nodeValue);
+ self::assertTrue($doc->elementExists('/w:document/w:body/w:p/w:r/w:rPr/w:b'));
}
/**
- * Tests parsing of ul/li
+ * Tests parsing of ul/li.
*/
- public function testOrderedListNumbering()
+ public function testOrderedListNumbering(): void
{
- $phpWord = new \PhpOffice\PhpWord\PhpWord();
+ $phpWord = new PhpWord();
$section = $phpWord->addSection();
$html = '
List 1 item 1
@@ -375,24 +820,24 @@ public function testOrderedListNumbering()
$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'));
+ self::assertTrue($doc->elementExists('/w:document/w:body/w:p/w:pPr/w:numPr/w:numId'));
+ self::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);
+ self::assertEquals('List 1 item 1', $doc->getElement('/w:document/w:body/w:p[1]/w:r/w:t')->nodeValue);
+ self::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);
+ self::assertNotEquals($firstListnumId, $secondListnumId);
}
/**
- * Tests parsing of nested ul/li
+ * Tests parsing of nested ul/li.
*/
- public function testOrderedNestedListNumbering()
+ public function testOrderedNestedListNumbering(): void
{
- $phpWord = new \PhpOffice\PhpWord\PhpWord();
+ $phpWord = new PhpWord();
$section = $phpWord->addSection();
$html = '
List 1 item 1
@@ -412,24 +857,24 @@ public function testOrderedNestedListNumbering()
$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'));
+ self::assertTrue($doc->elementExists('/w:document/w:body/w:p/w:pPr/w:numPr/w:numId'));
+ self::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);
+ self::assertEquals('List 1 item 1', $doc->getElement('/w:document/w:body/w:p[1]/w:r/w:t')->nodeValue);
+ self::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);
+ self::assertNotEquals($firstListnumId, $secondListnumId);
}
/**
- * Tests parsing of ul/li
+ * Tests parsing of ul/li.
*/
- public function testParseListWithFormat()
+ public function testParseListWithFormat(): void
{
- $phpWord = new \PhpOffice\PhpWord\PhpWord();
+ $phpWord = new PhpWord();
$section = $phpWord->addSection();
$html = preg_replace('/\s+/', ' ', '
Some text before
@@ -447,39 +892,39 @@ public function testParseListWithFormat()
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);
+ self::assertTrue($doc->elementExists('/w:document/w:body/w:p/w:pPr/w:numPr/w:numId'));
+ self::assertTrue($doc->elementExists('/w:document/w:body/w:p/w:r/w:t'));
+ self::assertEquals('list item2', $doc->getElement('/w:document/w:body/w:p[2]/w:r/w:t')->nodeValue);
+ self::assertTrue($doc->elementExists('/w:document/w:body/w:p[1]/w:r[3]/w:rPr/w:b'));
+ self::assertEquals('bold', $doc->getElement('/w:document/w:body/w:p[1]/w:r[3]/w:t')->nodeValue);
}
/**
- * Tests parsing of br
+ * Tests parsing of br.
*/
- public function testParseLineBreak()
+ public function testParseLineBreak(): void
{
- $phpWord = new \PhpOffice\PhpWord\PhpWord();
+ $phpWord = new PhpWord();
$section = $phpWord->addSection();
$html = 'This is some text with a linebreak.
';
Html::addHtml($section, $html);
$doc = TestHelperDOCX::getDocument($phpWord, 'Word2007');
- $this->assertTrue($doc->elementExists('/w:document/w:body/w:p/w:br'));
- $this->assertTrue($doc->elementExists('/w:document/w:body/w:p/w:r/w:t'));
- $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);
+ self::assertTrue($doc->elementExists('/w:document/w:body/w:p/w:br'));
+ self::assertTrue($doc->elementExists('/w:document/w:body/w:p/w:r/w:t'));
+ self::assertEquals('This is some text', $doc->getElement('/w:document/w:body/w:p/w:r[1]/w:t')->nodeValue);
+ self::assertEquals('with a linebreak.', $doc->getElement('/w:document/w:body/w:p/w:r[2]/w:t')->nodeValue);
}
/**
- * Test parsing of img
+ * Test parsing of img.
*/
- public function testParseImage()
+ public function testParseImage(): void
{
$src = __DIR__ . '/../_files/images/firefox.png';
- $phpWord = new \PhpOffice\PhpWord\PhpWord();
+ $phpWord = new PhpWord();
$section = $phpWord->addSection();
$html = '
';
Html::addHtml($section, $html);
@@ -487,21 +932,81 @@ public function testParseImage()
$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: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'));
+ 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'));
+ self::assertStringMatchesFormat('%Smso-position-horizontal:right%S', $doc->getElementAttribute($baseXpath . '[1]/w:pict/v:shape', 'style'));
+ 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 remote img
+ * Test parsing of img.
*/
- public function testParseRemoteImage()
+ 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.
+ */
+ public function testParseRemoteImage(): void
{
$src = self::getRemoteImageUrl();
- $phpWord = new \PhpOffice\PhpWord\PhpWord();
+ $phpWord = new PhpWord();
$section = $phpWord->addSection();
$html = '
';
Html::addHtml($section, $html);
@@ -509,15 +1014,33 @@ public function testParseRemoteImage()
$doc = TestHelperDOCX::getDocument($phpWord, 'Word2007');
$baseXpath = '/w:document/w:body/w:p/w:r';
- $this->assertTrue($doc->elementExists($baseXpath . '/w:pict/v:shape'));
+ self::assertTrue($doc->elementExists($baseXpath . '/w:pict/v:shape'));
}
/**
- * Test parsing embedded image
+ * Test parsing of remote img without extension.
*/
- public function testParseEmbeddedImage()
+ public function testParseRemoteImageWithoutExtension(): void
{
- $phpWord = new \PhpOffice\PhpWord\PhpWord();
+ $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.
+ */
+ public function testParseEmbeddedImage(): void
+ {
+ $phpWord = new PhpWord();
$section = $phpWord->addSection();
$html = '
';
Html::addHtml($section, $html);
@@ -525,22 +1048,22 @@ public function testParseEmbeddedImage()
$doc = TestHelperDOCX::getDocument($phpWord, 'Word2007');
$baseXpath = '/w:document/w:body/w:p/w:r';
- $this->assertTrue($doc->elementExists($baseXpath . '/w:pict/v:shape'));
+ self::assertTrue($doc->elementExists($baseXpath . '/w:pict/v:shape'));
}
/**
- * Test parsing of remote img that can be found locally
+ * Test parsing of remote img that can be found locally.
*/
- public function testParseRemoteLocalImage()
+ public function testParseRemoteLocalImage(): void
{
$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 = [
+ 'IMG_SRC_SEARCH' => 'https://fakedomain.io/images/',
+ 'IMG_SRC_REPLACE' => $localPath,
+ ];
- $phpWord = new \PhpOffice\PhpWord\PhpWord();
+ $phpWord = new PhpWord();
$section = $phpWord->addSection();
$html = '
';
Html::addHtml($section, $html, false, true, $options);
@@ -548,88 +1071,348 @@ public function testParseRemoteLocalImage()
$doc = TestHelperDOCX::getDocument($phpWord, 'Word2007');
$baseXpath = '/w:document/w:body/w:p/w:r';
- $this->assertTrue($doc->elementExists($baseXpath . '/w:pict/v:shape'));
+ self::assertTrue($doc->elementExists($baseXpath . '/w:pict/v:shape'));
}
/**
- * Test parsing of remote img that can be found locally
- *
- * @expectedException \Exception
+ * Test parsing of remote img that can be found locally.
*/
- public function testCouldNotLoadImage()
+ public function testCouldNotLoadImage(): void
{
+ $this->expectException(Exception::class);
$src = 'https://fakedomain.io/images/firefox.png';
- $phpWord = new \PhpOffice\PhpWord\PhpWord();
+ $phpWord = new PhpWord();
$section = $phpWord->addSection();
$html = '
';
Html::addHtml($section, $html, false, true);
}
- public function testParseLink()
+ public function testParseLink(): void
{
- $phpWord = new \PhpOffice\PhpWord\PhpWord();
+ $phpWord = new PhpWord();
$section = $phpWord->addSection();
- $html = 'link text
';
+ $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);
- $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'));
+ self::assertTrue($doc->elementExists('/w:document/w:body/w:p/w:hyperlink'));
+ 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'));
+ }
- $phpWord = new \PhpOffice\PhpWord\PhpWord();
+ public function testParseLink2(): void
+ {
+ $phpWord = new 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'));
+ self::assertTrue($doc->elementExists('/w:document/w:body/w:p/w:hyperlink'));
+ self::assertTrue($doc->getElement('/w:document/w:body/w:p/w:hyperlink')->hasAttribute('w:anchor'));
+ self::assertEquals('bookmark', $doc->getElement('/w:document/w:body/w:p/w:hyperlink')->getAttribute('w:anchor'));
+ }
+
+ public function testParseLinkAllowsAbsenceOfHref(): void
+ {
+ $phpWord = new 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 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()
+ public function testParseMalformedStyleIsIgnored(): void
{
- $phpWord = new \PhpOffice\PhpWord\PhpWord();
+ $phpWord = new 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'));
+ self::assertFalse($doc->elementExists('/w:document/w:body/w:p[1]/w:pPr/w:jc'));
}
/**
- * Tests parsing hidden text
+ * Tests parsing hidden text.
*/
- public function testParseHiddenText()
+ public function testParseHiddenText(): void
{
- $phpWord = new \PhpOffice\PhpWord\PhpWord();
+ $phpWord = new 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'));
+ self::assertTrue($doc->elementExists('/w:document/w:body/w:p/w:r/w:rPr/w:vanish'));
}
/**
- * Tests parsing letter spacing
+ * Tests parsing letter spacing.
*/
- public function testParseLetterSpacing()
+ public function testParseLetterSpacing(): void
{
- $phpWord = new \PhpOffice\PhpWord\PhpWord();
+ $phpWord = new 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'));
+ self::assertTrue($doc->elementExists('/w:document/w:body/w:p/w:r/w:rPr/w:spacing'));
+ self::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(): void
+ {
+ $phpWord = new PhpWord();
+ $section = $phpWord->addSection();
+ $html = ' ';
+ Html::addHtml($section, $html);
+
+ $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007');
+
+ self::assertTrue($doc->elementExists('/w:document/w:body/w:p[1]/w:r/w:fldChar/w:ffData/w:checkBox'));
+ self::assertEquals(1, $doc->getElement('/w:document/w:body/w:p[1]/w:r/w:fldChar/w:ffData/w:checkBox/w:checked')->getAttribute('w:val'));
+
+ self::assertTrue($doc->elementExists('/w:document/w:body/w:p[2]/w:r/w:fldChar/w:ffData/w:checkBox'));
+ self::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 horizontal rule.
+ */
+ public function testParseHorizontalRule(): void
+ {
+ $phpWord = new 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';
+ self::assertTrue($doc->elementExists($xpath));
+ self::assertEquals('single', $doc->getElement($xpath)->getAttribute('w:val')); // solid
+ self::assertEquals('1', $doc->getElement($xpath)->getAttribute('w:sz')); // 1 twip
+ self::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';
+ self::assertTrue($doc->elementExists($xpath));
+ self::assertEquals('single', $doc->getElement($xpath)->getAttribute('w:val'));
+ self::assertEquals((int) (5 * 15 / 2), $doc->getElement($xpath)->getAttribute('w:sz'));
+ self::assertEquals('lightblue', $doc->getElement($xpath)->getAttribute('w:color'));
+
+ $xpath = '/w:document/w:body/w:p[4]/w:pPr/w:spacing';
+ self::assertTrue($doc->elementExists($xpath));
+ self::assertEquals(450, $doc->getElement($xpath)->getAttribute('w:before'));
+ self::assertEquals(0, $doc->getElement($xpath)->getAttribute('w:after'));
+ self::assertEquals(240, $doc->getElement($xpath)->getAttribute('w:line'));
+ }
+
+ /**
+ * Parse ordered list start & numbering style.
+ */
+ public function testParseOrderedList(): void
+ {
+ $phpWord = new PhpWord();
+ $section = $phpWord->addSection();
+
+ // borders & backgrounds are here just for better visual comparison
+ $html = <<
+ standard ordered list line 1
+ standard ordered list line 2
+
+
+
+ ordered list alphabetical, line 5 => E
+ ordered list alphabetical, line 6 => F
+
+
+
+ ordered list roman lower, line 3 => iii
+ ordered list roman lower, line 4 => iv
+
+
+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';
+ self::assertTrue($doc->elementExists($xpath, $xmlFile));
+ self::assertEquals('1', $doc->getElement($xpath, $xmlFile)->getAttribute('w:val'));
+
+ $xpath = '/w:numbering/w:abstractNum[1]/w:lvl[1]/w:numFmt';
+ self::assertTrue($doc->elementExists($xpath, $xmlFile));
+ self::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';
+ self::assertTrue($doc->elementExists($xpath, $xmlFile));
+ self::assertEquals('5', $doc->getElement($xpath, $xmlFile)->getAttribute('w:val'));
+
+ $xpath = '/w:numbering/w:abstractNum[2]/w:lvl[1]/w:numFmt';
+ self::assertTrue($doc->elementExists($xpath, $xmlFile));
+ self::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';
+ self::assertTrue($doc->elementExists($xpath, $xmlFile));
+ self::assertEquals('3', $doc->getElement($xpath, $xmlFile)->getAttribute('w:val'));
+
+ $xpath = '/w:numbering/w:abstractNum[3]/w:lvl[1]/w:numFmt';
+ self::assertTrue($doc->elementExists($xpath, $xmlFile));
+ self::assertEquals('lowerRoman', $doc->getElement($xpath, $xmlFile)->getAttribute('w:val'));
+ }
+
+ /**
+ * Parse ordered list start & numbering style.
+ */
+ public function testParseVerticalAlign(): void
+ {
+ $phpWord = new PhpWord();
+ $section = $phpWord->addSection();
+
+ // borders & backgrounds are here just for better visual comparison
+ $html = <<
+
+ default
+ top
+ middle
+ bottom
+
+
+
+HTML;
+
+ Html::addHtml($section, $html);
+ $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007');
+
+ $xpath = '/w:document/w:body/w:tbl/w:tr/w:tc[1]/w:tcPr/w:vAlign';
+ self::assertFalse($doc->elementExists($xpath));
+
+ $xpath = '/w:document/w:body/w:tbl/w:tr/w:tc[2]/w:tcPr/w:vAlign';
+ self::assertTrue($doc->elementExists($xpath));
+ self::assertEquals('top', $doc->getElement($xpath)->getAttribute('w:val'));
+
+ $xpath = '/w:document/w:body/w:tbl/w:tr/w:tc[3]/w:tcPr/w:vAlign';
+ self::assertTrue($doc->elementExists($xpath));
+ self::assertEquals('center', $doc->getElement($xpath)->getAttribute('w:val'));
+
+ $xpath = '/w:document/w:body/w:tbl/w:tr/w:tc[4]/w:tcPr/w:vAlign';
+ self::assertTrue($doc->elementExists($xpath));
+ self::assertEquals('bottom', $doc->getElement($xpath)->getAttribute('w:val'));
+ }
+
+ /**
+ * Fix bug - don't decode double quotes inside double quoted string.
+ */
+ public function testDontDecodeAlreadyEncodedDoubleQuotes(): void
+ {
+ $phpWord = new 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');
+ 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],
+ ];
+ }
+
+ /**
+ * Test ruby.
+ */
+ public function testParseRubyHtml(): void
+ {
+ $html = <<
+ base text
+ (
+ ruby text
+ )
+
+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/Shared/Microsoft/PasswordEncoderTest.php b/tests/PhpWordTests/Shared/Microsoft/PasswordEncoderTest.php
new file mode 100644
index 0000000000..d3c13bf8b4
--- /dev/null
+++ b/tests/PhpWordTests/Shared/Microsoft/PasswordEncoderTest.php
@@ -0,0 +1,90 @@
+getDomFromString('AAA ');
+
+ self::assertTrue($reader->elementExists('/element/child'));
+ self::assertEquals('AAA', $reader->getElement('/element/child')->textContent);
+ self::assertEquals('AAA', $reader->getValue('/element/child'));
+ self::assertEquals('test', $reader->getAttribute('attr', $reader->getElement('/element')));
+ self::assertEquals('subtest', $reader->getAttribute('attr', $reader->getElement('/element'), 'child'));
+ }
+
+ /**
+ * Test reading XML from zip.
+ */
+ public function testDomFromZip(): 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'));
+ }
+
+ /**
+ * 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.
+ */
+ public function testThrowsExceptionOnNonExistingArchive(): void
+ {
+ $this->expectException(Exception::class);
+ $archiveFile = __DIR__ . '/../_files/xml/readers.zip';
+
+ $reader = new XMLReader();
+ $reader->getDomFromZip($archiveFile, 'test.xml');
+ }
+
+ /**
+ * Test that read from invalid archive throws exception.
+ */
+ public function testThrowsExceptionOnZipArchiveOpenErrors(): void
+ {
+ $tempPath = tempnam(sys_get_temp_dir(), 'PhpWord') ?: 'tempNameFile';
+
+ // 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.
+ */
+ public function testCountElements(): void
+ {
+ $reader = new XMLReader();
+ $reader->getDomFromString('AAA BBB ');
+
+ self::assertEquals(2, $reader->countElements('/element/child'));
+ }
+
+ /**
+ * Test read non existing elements.
+ */
+ public function testReturnNullOnNonExistingNode(): void
+ {
+ $reader = new XMLReader();
+ self::assertSame(0, $reader->getElements('/element/children')->length);
+ $reader->getDomFromString('AAA ');
+
+ self::assertNull($reader->getElement('/element/children'));
+ self::assertNull($reader->getValue('/element/children'));
+ }
+
+ /**
+ * Test that xpath fails if custom namespace is not registered.
+ */
+ public function testShouldThrowExceptionIfNamespaceIsNotKnown(): void
+ {
+ try {
+ $reader = new XMLReader();
+ $reader->getDomFromString('AAA ');
+
+ self::assertTrue($reader->elementExists('/element/test:child'));
+ self::assertEquals('AAA', $reader->getElement('/element/test:child')->textContent);
+ self::fail();
+ } catch (Exception $e) {
+ // @phpstan-ignore-next-line
+ self::assertTrue(true);
+ }
+ }
+
+ /**
+ * Test reading XML with manually registered namespace.
+ */
+ public function testShouldParseXmlWithCustomNamespace(): void
+ {
+ $reader = new XMLReader();
+ $reader->getDomFromString('AAA ');
+ $reader->registerNamespace('test', 'http://phpword.com/my/custom/namespace');
+
+ self::assertTrue($reader->elementExists('/element/test:child'));
+ self::assertEquals('AAA', $reader->getElement('/element/test:child')->textContent);
+ }
+
+ /**
+ * Test that xpath fails if custom namespace is not registered.
+ */
+ public function testShouldThowExceptionIfTryingToRegisterNamespaceBeforeReadingDoc(): void
+ {
+ $this->expectException(InvalidArgumentException::class);
+ $reader = new XMLReader();
+ $reader->registerNamespace('test', 'http://phpword.com/my/custom/namespace');
+ }
+}
diff --git a/tests/PhpWordTests/Shared/XMLWriterTest.php b/tests/PhpWordTests/Shared/XMLWriterTest.php
new file mode 100644
index 0000000000..476b8b3ba9
--- /dev/null
+++ b/tests/PhpWordTests/Shared/XMLWriterTest.php
@@ -0,0 +1,74 @@
+startElement('element');
+ $object->text('AAA');
+ $object->endElement();
+ self::assertEquals('AAA ' . chr(10), $object->getData());
+
+ // Disk
+ $object = new XMLWriter(XMLWriter::STORAGE_DISK);
+ $object->startElement('element');
+ $object->text('BBB');
+ $object->endElement();
+ self::assertEquals('BBB ' . chr(10), $object->getData());
+ }
+
+ public function testWriteAttribute(): void
+ {
+ $xmlWriter = new XMLWriter();
+ $xmlWriter->startElement('element');
+ $xmlWriter->writeAttribute('name', 'value');
+ $xmlWriter->endElement();
+
+ self::assertSame(' ' . chr(10), $xmlWriter->getData());
+ }
+
+ public function testWriteAttributeShouldWriteFloatValueLocaleIndependent(): void
+ {
+ $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');
+
+ self::assertSame(' ' . chr(10), $xmlWriter->getData());
+
+ setlocale(LC_NUMERIC, $currentLocale);
+ }
+}
diff --git a/tests/PhpWord/Shared/ZipArchiveTest.php b/tests/PhpWordTests/Shared/ZipArchiveTest.php
similarity index 74%
rename from tests/PhpWord/Shared/ZipArchiveTest.php
rename to tests/PhpWordTests/Shared/ZipArchiveTest.php
index ecd0961e24..3f998c26ef 100644
--- a/tests/PhpWord/Shared/ZipArchiveTest.php
+++ b/tests/PhpWordTests/Shared/ZipArchiveTest.php
@@ -1,4 +1,5 @@
*/
- public function testZipArchive($zipClass = 'ZipArchive')
+ public function testZipArchive($zipClass = 'ZipArchive'): void
{
// Preparation
$existingFile = __DIR__ . '/../_files/documents/sheet.xls';
@@ -82,19 +84,19 @@ public function testZipArchive($zipClass = 'ZipArchive')
$object->open($zipFile);
// Run tests
- $this->assertEquals(0, $object->locateName('xls/new.xls'));
- $this->assertFalse($object->locateName('blablabla'));
+ self::assertEquals(0, $object->locateName('xls/new.xls'));
+ self::assertFalse($object->locateName('blablabla'));
- $this->assertEquals('Test', $object->getFromName('content/string.txt'));
- $this->assertEquals('Test', $object->getFromName('/content/string.txt'));
+ self::assertEquals('Test', $object->getFromName('content/string.txt'));
+ self::assertEquals('Test', $object->getFromName('/content/string.txt'));
- $this->assertFalse($object->getNameIndex(-1));
- $this->assertEquals('content/string.txt', $object->getNameIndex(1));
+ self::assertFalse($object->getNameIndex(-1));
+ self::assertEquals('content/string.txt', $object->getNameIndex(1));
- $this->assertFalse($object->extractTo('blablabla'));
- $this->assertTrue($object->extractTo($destination1));
- $this->assertTrue($object->extractTo($destination2, 'xls/new.xls'));
- $this->assertFalse($object->extractTo($destination2, 'blablabla'));
+ self::assertFalse($object->extractTo('blablabla'));
+ self::assertTrue($object->extractTo($destination1));
+ self::assertTrue($object->extractTo($destination2, 'xls/new.xls'));
+ self::assertFalse($object->extractTo($destination2, 'blablabla'));
// Cleanup
$this->deleteDir($destination1);
@@ -103,21 +105,19 @@ public function testZipArchive($zipClass = 'ZipArchive')
}
/**
- * Test PclZip
- *
- * @covers ::
+ * Test PclZip.
*/
- public function testPCLZip()
+ public function testPCLZip(): void
{
$this->testZipArchive('PhpOffice\PhpWord\Shared\ZipArchive');
}
/**
- * Delete directory
+ * Delete directory.
*
* @param string $dir
*/
- private function deleteDir($dir)
+ private function deleteDir($dir): void
{
foreach (scandir($dir) as $file) {
if ('.' === $file || '..' === $file) {
diff --git a/tests/PhpWordTests/Style/AbstractStyleTest.php b/tests/PhpWordTests/Style/AbstractStyleTest.php
new file mode 100644
index 0000000000..679c9f5e49
--- /dev/null
+++ b/tests/PhpWordTests/Style/AbstractStyleTest.php
@@ -0,0 +1,141 @@
+getMockForAbstractClass(AbstractStyle::class);
+ } else {
+ /** @var AbstractStyle $stub */
+ $stub = new class() extends AbstractStyle {
+ };
+ }
+ $stub->setStyleByArray(['index' => 1]);
+
+ self::assertEquals(1, $stub->getIndex());
+ }
+
+ public function testSetStyleByArrayWithAlign(): void
+ {
+ $stub = new Paragraph();
+ $stub->setStyleByArray(['align' => Jc::CENTER]);
+
+ self::assertEquals(Jc::CENTER, $stub->getAlignment());
+ }
+
+ public function testSetStyleByArrayWithAlignment(): void
+ {
+ $stub = new Paragraph();
+ $stub->setStyleByArray(['alignment' => Jc::CENTER]);
+
+ self::assertEquals(Jc::CENTER, $stub->getAlignment());
+ }
+
+ /**
+ * Test setBoolVal, setIntVal, setFloatVal, setEnumVal with normal value.
+ */
+ public function testSetValNormal(): void
+ {
+ // @phpstan-ignore-next-line
+ 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]));
+ self::assertEquals(871.1, self::callProtectedMethod($stub, 'setFloatVal', [871.1, 2.1]));
+ self::assertEquals(871.1, self::callProtectedMethod($stub, 'setFloatVal', ['871.1', 2.1]));
+ self::assertEquals('a', self::callProtectedMethod($stub, 'setEnumVal', ['a', ['a', 'b'], 'b']));
+ }
+
+ /**
+ * Test setBoolVal, setIntVal, setFloatVal, setEnumVal with default value.
+ */
+ public function testSetValDefault(): void
+ {
+ // @phpstan-ignore-next-line
+ 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]));
+ self::assertEquals(2.1, self::callProtectedMethod($stub, 'setFloatVal', ['foo', 2.1]));
+ self::assertEquals('b', self::callProtectedMethod($stub, 'setEnumVal', [null, ['a', 'b'], 'b']));
+ }
+
+ /**
+ * Test setEnumVal exception.
+ */
+ public function testSetValEnumException(): void
+ {
+ $this->expectException(InvalidArgumentException::class);
+ // @phpstan-ignore-next-line
+ 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']));
+ }
+
+ /**
+ * Helper function to call protected method.
+ *
+ * @param mixed $object
+ * @param string $method
+ */
+ public static function callProtectedMethod($object, $method, array $args = [])
+ {
+ $class = new ReflectionClass(get_class($object));
+ $method = $class->getMethod($method);
+ $method->setAccessible(true);
+
+ return $method->invokeArgs($object, $args);
+ }
+}
diff --git a/tests/PhpWordTests/Style/CellTest.php b/tests/PhpWordTests/Style/CellTest.php
new file mode 100644
index 0000000000..56b099c05f
--- /dev/null
+++ b/tests/PhpWordTests/Style/CellTest.php
@@ -0,0 +1,127 @@
+ 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',
+ 'borderTopColor' => 'FFFF00',
+ 'borderLeftColor' => 'FFFF00',
+ 'borderRightColor' => 'FFFF00',
+ 'borderBottomColor' => 'FFFF00',
+ 'vMerge' => Cell::VMERGE_RESTART,
+ ] 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());
+ }
+ }
+
+ /**
+ * Test border color.
+ */
+ public function testBorderColor(): void
+ {
+ $object = new Cell();
+
+ $value = 'FF0000';
+
+ $object->setStyleValue('borderColor', $value);
+ $expected = [$value, $value, $value, $value];
+ self::assertEquals($expected, $object->getBorderColor());
+ }
+
+ /**
+ * Test border size.
+ */
+ public function testBorderSize(): void
+ {
+ $object = new Cell();
+
+ $value = 120;
+ $expected = [$value, $value, $value, $value];
+ $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/Style/ChartTest.php b/tests/PhpWordTests/Style/ChartTest.php
new file mode 100644
index 0000000000..e8e75901d7
--- /dev/null
+++ b/tests/PhpWordTests/Style/ChartTest.php
@@ -0,0 +1,188 @@
+getWidth(), 1000000);
+
+ $chart->setWidth(200);
+
+ self::assertEquals($chart->getWidth(), 200);
+ }
+
+ /**
+ * Testing getter and setter for chart height.
+ */
+ public function testSetGetHeight(): void
+ {
+ $chart = new Chart();
+
+ self::assertEquals($chart->getHeight(), 1000000);
+
+ $chart->setHeight(200);
+
+ self::assertEquals($chart->getHeight(), 200);
+ }
+
+ /**
+ * Testing getter and setter for is3d.
+ */
+ public function testSetIs3d(): void
+ {
+ $chart = new Chart();
+
+ self::assertEquals($chart->is3d(), false);
+
+ $chart->set3d(true);
+
+ self::assertEquals($chart->is3d(), true);
+ }
+
+ /**
+ * Testing getter and setter for chart colors.
+ */
+ public function testSetGetColors(): void
+ {
+ $chart = new Chart();
+
+ self::assertIsArray($chart->getColors());
+
+ self::assertEquals(count($chart->getColors()), 0);
+
+ $chart->setColors(['FFFFFFFF', 'FF000000', 'FFFF0000']);
+
+ self::assertEquals($chart->getColors(), ['FFFFFFFF', 'FF000000', 'FFFF0000']);
+ }
+
+ /**
+ * Testing getter and setter for dataLabelOptions.
+ */
+ public function testSetGetDataLabelOptions(): void
+ {
+ $chart = new Chart();
+
+ $originalDataLabelOptions = [
+ 'showVal' => true,
+ 'showCatName' => true,
+ 'showLegendKey' => false,
+ 'showSerName' => false,
+ 'showPercent' => false,
+ 'showLeaderLines' => false,
+ 'showBubbleSize' => false,
+ ];
+
+ self::assertEquals($chart->getDataLabelOptions(), $originalDataLabelOptions);
+
+ $changedDataLabelOptions = [
+ 'showVal' => false,
+ 'showCatName' => false,
+ 'showLegendKey' => true,
+ 'showSerName' => true,
+ 'showPercent' => true,
+ 'showLeaderLines' => true,
+ 'showBubbleSize' => true,
+ ];
+
+ $chart->setDataLabelOptions(
+ [
+ 'showVal' => false,
+ 'showCatName' => false,
+ 'showLegendKey' => true,
+ 'showSerName' => true,
+ 'showPercent' => true,
+ 'showLeaderLines' => true,
+ 'showBubbleSize' => true,
+ ]
+ );
+ self::assertEquals($chart->getDataLabelOptions(), $changedDataLabelOptions);
+ }
+
+ /**
+ * Testing categoryLabelPosition getter and setter.
+ */
+ public function testSetGetCategoryLabelPosition(): void
+ {
+ $chart = new Chart();
+
+ self::assertEquals($chart->getCategoryLabelPosition(), 'nextTo');
+
+ $chart->setCategoryLabelPosition('high');
+
+ self::assertEquals($chart->getCategoryLabelPosition(), 'high');
+ }
+
+ /**
+ * Testing valueLabelPosition getter and setter.
+ */
+ public function testSetGetValueLabelPosition(): void
+ {
+ $chart = new Chart();
+
+ self::assertEquals($chart->getValueLabelPosition(), 'nextTo');
+
+ $chart->setValueLabelPosition('low');
+
+ self::assertEquals($chart->getValueLabelPosition(), 'low');
+ }
+
+ /**
+ * Testing categoryAxisTitle getter and setter.
+ */
+ public function testSetGetCategoryAxisTitle(): void
+ {
+ $chart = new Chart();
+
+ self::assertEquals($chart->getCategoryAxisTitle(), null);
+
+ $chart->setCategoryAxisTitle('Test Category Axis Title');
+
+ self::assertEquals($chart->getCategoryAxisTitle(), 'Test Category Axis Title');
+ }
+
+ /**
+ * Testing valueAxisTitle getter and setter.
+ */
+ public function testSetGetValueAxisTitle(): void
+ {
+ $chart = new Chart();
+
+ self::assertEquals($chart->getValueAxisTitle(), null);
+
+ $chart->setValueAxisTitle('Test Value Axis Title');
+
+ self::assertEquals($chart->getValueAxisTitle(), 'Test Value Axis Title');
+ }
+}
diff --git a/tests/PhpWordTests/Style/FontTest.php b/tests/PhpWordTests/Style/FontTest.php
new file mode 100644
index 0000000000..4ba6a762f3
--- /dev/null
+++ b/tests/PhpWordTests/Style/FontTest.php
@@ -0,0 +1,228 @@
+ Jc::BOTH]);
+
+ self::assertEquals('text', $object->getStyleType());
+ self::assertInstanceOf(\PhpOffice\PhpWord\Style\Paragraph::class, $object->getParagraph());
+ self::assertIsArray($object->getStyleValues());
+ }
+
+ /**
+ * Test setting style values with null or empty value.
+ */
+ public function testSetStyleValueWithNullOrEmpty(): void
+ {
+ $object = new Font();
+
+ $attributes = [
+ '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,
+ 'rtl' => false,
+ 'fgColor' => null,
+ 'bgColor' => null,
+ 'scale' => null,
+ 'spacing' => null,
+ 'kerning' => null,
+ 'lang' => null,
+ 'hidden' => false,
+ 'whiteSpace' => '',
+ 'fallbackFont' => '',
+ ];
+ foreach ($attributes as $key => $default) {
+ $get = is_bool($default) ? "is{$key}" : "get{$key}";
+ self::assertEquals($default, $object->$get());
+ $object->setStyleValue($key, null);
+ self::assertEquals($default, $object->$get());
+ $object->setStyleValue($key, '');
+ self::assertEquals($default, $object->$get());
+ }
+ }
+
+ /**
+ * Test setting style values with normal value.
+ */
+ public function testSetStyleValueNormal(): void
+ {
+ $object = new Font();
+
+ $attributes = [
+ '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,
+ 'rtl' => true,
+ 'noProof' => true,
+ 'lang' => new Language(Language::EN_US),
+ 'hidden' => true,
+ 'whiteSpace' => 'pre-wrap',
+ 'fallbackFont' => 'serif',
+ ];
+ $object->setStyleByArray($attributes);
+ foreach ($attributes as $key => $value) {
+ $get = is_bool($value) ? "is{$key}" : "get{$key}";
+ self::assertEquals($value, $object->$get());
+ }
+ }
+
+ /**
+ * Test set line height.
+ */
+ public function testLineHeight(): void
+ {
+ $phpWord = new PhpWord();
+ $section = $phpWord->addSection();
+
+ // Test style array
+ $text = $section->addText('This is a test', ['line-height' => 2.0]);
+
+ $doc = TestHelperDOCX::getDocument($phpWord);
+ $element = $doc->getElement('/w:document/w:body/w:p/w:pPr/w:spacing');
+
+ $lineHeight = $element->getAttribute('w:line');
+ $lineRule = $element->getAttribute('w:lineRule');
+
+ self::assertEquals(480, $lineHeight);
+ 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');
+
+ $lineHeight = $element->getAttribute('w:line');
+ $lineRule = $element->getAttribute('w:lineRule');
+
+ self::assertEquals(720, $lineHeight);
+ self::assertEquals('auto', $lineRule);
+ }
+
+ /**
+ * Test line height floatval.
+ */
+ public function testLineHeightFloatval(): void
+ {
+ $object = new Font(null, ['alignment' => Jc::CENTER]);
+ $object->setLineHeight('1.5pt');
+ self::assertEquals(1.5, $object->getLineHeight());
+ }
+
+ /**
+ * Test line height exception by using nonnumeric value.
+ */
+ public function testLineHeightException(): void
+ {
+ $this->expectException(\PhpOffice\PhpWord\Exception\InvalidStyleException::class);
+ $object = new Font();
+ $object->setLineHeight('a');
+ }
+
+ /**
+ * Test setting the language as a string.
+ */
+ public function testSetLangAsString(): void
+ {
+ $object = new Font();
+ $object->setLang(Language::FR_BE);
+ 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/ImageTest.php b/tests/PhpWordTests/Style/ImageTest.php
new file mode 100644
index 0000000000..759a85441e
--- /dev/null
+++ b/tests/PhpWordTests/Style/ImageTest.php
@@ -0,0 +1,108 @@
+ 200,
+ 'height' => 200,
+ 'marginTop' => 240,
+ 'marginLeft' => 240,
+ 'wrapDistanceLeft' => 10,
+ 'wrapDistanceRight' => 20,
+ 'wrapDistanceTop' => 30,
+ 'wrapDistanceBottom' => 40,
+ ] 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);
+ self::assertEquals($value, $object->$get());
+ }
+ }
+
+ /**
+ * Test setStyleValue method.
+ */
+ public function testSetStyleValue(): void
+ {
+ $object = new Image();
+
+ $properties = [
+ 'width' => 200,
+ 'height' => 200,
+ 'alignment' => Jc::START,
+ 'marginTop' => 240,
+ 'marginLeft' => 240,
+ 'position' => 10,
+ '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,
+ 'wrapDistanceBottom' => 40,
+ ];
+ foreach ($properties as $key => $value) {
+ $get = "get{$key}";
+ $object->setStyleValue("{$key}", $value);
+ self::assertEquals($value, $object->$get());
+ }
+ }
+
+ /**
+ * Test setWrappingStyle exception.
+ */
+ public function testSetWrappingStyleException(): void
+ {
+ $this->expectException(InvalidArgumentException::class);
+ $object = new Image();
+ $object->setWrappingStyle('foo');
+ }
+}
diff --git a/tests/PhpWord/Style/IndentationTest.php b/tests/PhpWordTests/Style/IndentationTest.php
similarity index 61%
rename from tests/PhpWord/Style/IndentationTest.php
rename to tests/PhpWordTests/Style/IndentationTest.php
index b39a4d771d..76e3c74cb7 100644
--- a/tests/PhpWord/Style/IndentationTest.php
+++ b/tests/PhpWordTests/Style/IndentationTest.php
@@ -1,4 +1,5 @@
array(0, 10),
- 'right' => array(0, 10),
- 'firstLine' => array(null, 20),
- 'hanging' => array(null, 20),
- );
+ $properties = [
+ 'left' => [0, 10],
+ 'right' => [0, 10],
+ 'firstLine' => [null, 20],
+ 'firstLineChars' => [0, 20],
+ 'hanging' => [null, 20],
+ ];
foreach ($properties as $property => $value) {
- list($default, $expected) = $value;
+ [$default, $expected] = $value;
$get = "get{$property}";
$set = "set{$property}";
- $this->assertEquals($default, $object->$get()); // Default value
+ self::assertEquals($default, $object->$get()); // Default value
$object->$set($expected);
- $this->assertEquals($expected, $object->$get()); // New value
+ self::assertEquals($expected, $object->$get()); // New value
}
}
}
diff --git a/tests/PhpWordTests/Style/LanguageTest.php b/tests/PhpWordTests/Style/LanguageTest.php
new file mode 100644
index 0000000000..848284e5e3
--- /dev/null
+++ b/tests/PhpWordTests/Style/LanguageTest.php
@@ -0,0 +1,92 @@
+ [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();
+ foreach ([
+ 'latin' => [null, 'fr-BE'],
+ 'eastAsia' => [null, 'ja-JP'],
+ 'bidirectional' => [null, 'ar-SA'],
+ ] 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 throws exception if wrong locale is given.
+ */
+ public function testWrongLanguage(): void
+ {
+ $this->expectException(InvalidArgumentException::class);
+ $language = new Language();
+ $language->setLatin('fra');
+ }
+
+ /**
+ * Tests that a language can be set with just a 2 char code.
+ */
+ public function testShortLanguage(): void
+ {
+ //when
+ $language = new Language();
+ $language->setLatin('fr');
+
+ //then
+ Assert::assertEquals('fr-FR', $language->getLatin());
+ }
+}
diff --git a/tests/PhpWordTests/Style/LineNumberingTest.php b/tests/PhpWordTests/Style/LineNumberingTest.php
new file mode 100644
index 0000000000..c76bddf56c
--- /dev/null
+++ b/tests/PhpWordTests/Style/LineNumberingTest.php
@@ -0,0 +1,67 @@
+ [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'],
+ ] 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
+ }
+ }
+}
diff --git a/tests/PhpWordTests/Style/LineTest.php b/tests/PhpWordTests/Style/LineTest.php
new file mode 100644
index 0000000000..26049d5cd8
--- /dev/null
+++ b/tests/PhpWordTests/Style/LineTest.php
@@ -0,0 +1,162 @@
+ 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,
+ 'color' => 'red',
+ ] as $key => $value) {
+ $set = "set{$key}";
+ $get = "get{$key}";
+ $object->$set($value);
+ self::assertEquals($value, $object->$get());
+ }
+ }
+
+ /**
+ * Test setStyleValue method.
+ */
+ public function testSetStyleValue(): void
+ {
+ $object = new Line();
+
+ $properties = [
+ '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) {
+ $get = "get{$key}";
+ $object->setStyleValue("{$key}", $value);
+ self::assertEquals($value, $object->$get());
+ }
+ }
+
+ /**
+ * Test set/get flip.
+ */
+ public function testSetGetFlip(): void
+ {
+ $expected = true;
+ $object = new Line();
+ $object->setFlip($expected);
+ self::assertEquals($expected, $object->isFlip());
+ }
+
+ /**
+ * Test set/get connectorType.
+ */
+ public function testSetGetConnectorType(): void
+ {
+ $expected = Line::CONNECTOR_TYPE_STRAIGHT;
+ $object = new Line();
+ $object->setConnectorType($expected);
+ self::assertEquals($expected, $object->getConnectorType());
+ }
+
+ /**
+ * Test set/get weight.
+ */
+ public function testSetGetWeight(): void
+ {
+ $expected = 10;
+ $object = new Line();
+ $object->setWeight($expected);
+ self::assertEquals($expected, $object->getWeight());
+ }
+
+ /**
+ * Test set/get color.
+ */
+ public function testSetGetColor(): void
+ {
+ $expected = 'red';
+ $object = new Line();
+ $object->setColor($expected);
+ self::assertEquals($expected, $object->getColor());
+ }
+
+ /**
+ * Test set/get dash.
+ */
+ public function testSetGetDash(): void
+ {
+ $expected = Line::DASH_STYLE_LONG_DASH_DOT_DOT;
+ $object = new Line();
+ $object->setDash($expected);
+ self::assertEquals($expected, $object->getDash());
+ }
+
+ /**
+ * Test set/get beginArrow.
+ */
+ public function testSetGetBeginArrow(): void
+ {
+ $expected = Line::ARROW_STYLE_BLOCK;
+ $object = new Line();
+ $object->setBeginArrow($expected);
+ self::assertEquals($expected, $object->getBeginArrow());
+ }
+
+ /**
+ * Test set/get endArrow.
+ */
+ public function testSetGetEndArrow(): void
+ {
+ $expected = Line::ARROW_STYLE_CLASSIC;
+ $object = new Line();
+ $object->setEndArrow($expected);
+ self::assertEquals($expected, $object->getEndArrow());
+ }
+}
diff --git a/tests/PhpWord/Style/ListItemTest.php b/tests/PhpWordTests/Style/ListItemTest.php
similarity index 66%
rename from tests/PhpWord/Style/ListItemTest.php
rename to tests/PhpWordTests/Style/ListItemTest.php
index 71598e8030..59cdfeeda1 100644
--- a/tests/PhpWord/Style/ListItemTest.php
+++ b/tests/PhpWordTests/Style/ListItemTest.php
@@ -1,4 +1,5 @@
assertEquals($value, $object->getListType());
+ self::assertEquals($value, $object->getListType());
}
/**
- * Test set style value
+ * Test set style value.
*/
- public function testSetStyleValue()
+ public function testSetStyleValue(): void
{
$object = new ListItem();
$value = ListItem::TYPE_ALPHANUM;
$object->setStyleValue('listType', $value);
- $this->assertEquals($value, $object->getListType());
+ self::assertEquals($value, $object->getListType());
}
/**
- * Test list type
+ * Test list type.
*/
- public function testListType()
+ public function testListType(): void
{
$object = new ListItem();
$value = ListItem::TYPE_ALPHANUM;
$object->setListType($value);
- $this->assertEquals($value, $object->getListType());
+ self::assertEquals($value, $object->getListType());
}
/**
- * Test set/get numbering style name
+ * Test set/get numbering style name.
*/
- public function testSetGetNumStyle()
+ public function testSetGetNumStyle(): void
{
$expected = 'List Name';
$object = new ListItem();
$object->setNumStyle($expected);
- $this->assertEquals($expected, $object->getNumStyle());
+ self::assertEquals($expected, $object->getNumStyle());
}
}
diff --git a/tests/PhpWord/Style/NumberingLevelTest.php b/tests/PhpWordTests/Style/NumberingLevelTest.php
similarity index 50%
rename from tests/PhpWord/Style/NumberingLevelTest.php
rename to tests/PhpWordTests/Style/NumberingLevelTest.php
index 008a1fc5b5..b34e445e94 100644
--- a/tests/PhpWord/Style/NumberingLevelTest.php
+++ b/tests/PhpWordTests/Style/NumberingLevelTest.php
@@ -1,4 +1,5 @@
1,
+ 'start' => 1,
+ '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 = array(
- 'level' => 1,
- 'start' => 1,
- 'format' => 'decimal',
- 'restart' => 1,
- 'pStyle' => 'pStyle',
- 'suffix' => 'space',
- 'text' => '%1.',
+ $attributes = [
+ 'format' => 'decimal',
+ 'pStyle' => 'pStyle',
+ 'suffix' => 'space',
+ 'text' => '%1.',
'alignment' => Jc::START,
- 'left' => 360,
- 'hanging' => 360,
- 'tabPos' => 360,
- 'font' => 'Arial',
- 'hint' => 'default',
- );
+ 'font' => 'Arial',
+ 'hint' => 'default',
+ ];
foreach ($attributes as $key => $value) {
$set = "set{$key}";
$get = "get{$key}";
$object->$set($value);
- $this->assertEquals($value, $object->$get());
+ self::assertEquals($value, $object->$get());
}
}
}
diff --git a/tests/PhpWordTests/Style/NumberingTest.php b/tests/PhpWordTests/Style/NumberingTest.php
new file mode 100644
index 0000000000..153e4b9284
--- /dev/null
+++ b/tests/PhpWordTests/Style/NumberingTest.php
@@ -0,0 +1,72 @@
+ [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'],
+ ] 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 testGetLevels(): void
+ {
+ $object = new Numbering();
+
+ self::assertEmpty($object->getLevels());
+ }
+}
diff --git a/tests/PhpWord/Style/PaperTest.php b/tests/PhpWordTests/Style/PaperTest.php
similarity index 51%
rename from tests/PhpWord/Style/PaperTest.php
rename to tests/PhpWordTests/Style/PaperTest.php
index f8f0070180..ea5a4fb674 100644
--- a/tests/PhpWord/Style/PaperTest.php
+++ b/tests/PhpWordTests/Style/PaperTest.php
@@ -1,4 +1,5 @@
assertEquals('A4', $object->getSize());
+ self::assertEquals('A4', $object->getSize());
}
/**
- * Test paper size for B5 format
+ * Test paper size for B5 format.
*/
- public function testB5Size()
+ public function testB5Size(): void
{
$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);
+ self::assertEquals('B5', $object->getSize());
+ self::assertEqualsWithDelta(9977.9527559055, $object->getWidth(), 0.000000001);
+ self::assertEqualsWithDelta(14173.228346457, $object->getHeight(), 0.000000001);
}
/**
- * Test paper size for Folio format
+ * Test paper size for Folio format.
*/
- public function testFolioSize()
+ public function testFolioSize(): void
{
$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);
+ self::assertEquals('Folio', $object->getSize());
+ self::assertEqualsWithDelta(12240, $object->getWidth(), 0.1);
+ self::assertEqualsWithDelta(18720, $object->getHeight(), 0.1);
}
}
diff --git a/tests/PhpWordTests/Style/ParagraphTest.php b/tests/PhpWordTests/Style/ParagraphTest.php
new file mode 100644
index 0000000000..67645fa4d8
--- /dev/null
+++ b/tests/PhpWordTests/Style/ParagraphTest.php
@@ -0,0 +1,385 @@
+ true,
+ 'keepNext' => false,
+ 'keepLines' => false,
+ 'pageBreakBefore' => false,
+ 'contextualSpacing' => false,
+ ];
+ foreach ($attributes as $key => $default) {
+ $get = $this->findGetter($key, $default, $object);
+ $object->setStyleValue($key, null);
+ self::assertEquals($default, $object->$get());
+ $object->setStyleValue($key, '');
+ self::assertEquals($default, $object->$get());
+ }
+ }
+
+ /**
+ * Test setting style values with normal value.
+ */
+ public function testSetStyleValueNormal(): void
+ {
+ $object = new Paragraph();
+
+ $attributes = [
+ '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);
+ $object->setStyleValue("$key", $value);
+ if (('indent' == $key || 'hanging' == $key) && is_numeric($value)) {
+ $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)) {
+ if (method_exists($object, "is{$key}")) {
+ return "is{$key}";
+ } elseif (method_exists($object, "has{$key}")) {
+ return "has{$key}";
+ }
+ }
+
+ return "get{$key}";
+ }
+
+ /**
+ * Test get null style value.
+ */
+ public function testGetNullStyleValue(): void
+ {
+ $object = new Paragraph();
+
+ $attributes = ['spacing', 'indent', 'hanging', 'spaceBefore', 'spaceAfter', 'textAlignment'];
+ foreach ($attributes as $key) {
+ $get = $this->findGetter($key, null, $object);
+ self::assertNull($object->$get());
+ }
+ }
+
+ /**
+ * Test tabs.
+ */
+ public function testTabs(): void
+ {
+ $object = new Paragraph();
+ $object->setTabs([new Tab('left', 1550), new Tab('right', 5300)]);
+ self::assertCount(2, $object->getTabs());
+ }
+
+ public function testHanging(): void
+ {
+ $rand = mt_rand(0, 255);
+
+ $object = new Paragraph();
+ self::assertNull($object->getHanging());
+
+ $object->setHanging($rand);
+ self::assertEquals($rand, $object->getHanging());
+
+ $object->setHanging(null);
+ self::assertNull($object->getHanging());
+
+ $object->setHanging($rand);
+ self::assertEquals($rand, $object->getHanging());
+
+ $object->setHanging();
+ self::assertNull($object->getHanging());
+ }
+
+ public function testIndent(): void
+ {
+ $rand = mt_rand(0, 255);
+
+ $object = new Paragraph();
+ self::assertNull($object->getIndent());
+
+ $object->setIndent($rand);
+ self::assertEquals($rand, $object->getIndent());
+
+ $object->setIndent(null);
+ self::assertNull($object->getIndent());
+
+ $object->setIndent($rand);
+ self::assertEquals($rand, $object->getIndent());
+
+ $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
+ $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
+ $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
+ $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
+ $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
+ $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
+ $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
+ $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());
+ $object->setIndentFirstLine($rand);
+ self::assertEquals($rand, $object->getIndentFirstLine());
+ $object->setIndentFirstLine(null);
+ self::assertNull($object->getIndentFirstLine());
+ $object->setIndentFirstLine($rand);
+ self::assertEquals($rand, $object->getIndentFirstLine());
+ $object->setIndentFirstLine();
+ self::assertNull($object->getIndentFirstLine());
+ }
+
+ public function testIndentLeft(): void
+ {
+ $rand = mt_rand(0, 255);
+
+ $object = new Paragraph();
+ self::assertNull($object->getIndentLeft());
+ $object->setIndentLeft($rand);
+ self::assertEquals($rand, $object->getIndentLeft());
+ $object->setIndentLeft(null);
+ self::assertNull($object->getIndentLeft());
+ $object->setIndentLeft($rand);
+ self::assertEquals($rand, $object->getIndentLeft());
+ $object->setIndentLeft();
+ self::assertNull($object->getIndentLeft());
+ }
+
+ public function testIndentRight(): void
+ {
+ $rand = mt_rand(0, 255);
+
+ $object = new Paragraph();
+ self::assertNull($object->getIndentRight());
+ $object->setIndentRight($rand);
+ self::assertEquals($rand, $object->getIndentRight());
+ $object->setIndentRight(null);
+ self::assertNull($object->getIndentRight());
+ $object->setIndentRight($rand);
+ self::assertEquals($rand, $object->getIndentRight());
+ $object->setIndentRight();
+ self::assertNull($object->getIndentRight());
+ }
+
+ /**
+ * Line height.
+ */
+ public function testLineHeight(): void
+ {
+ $phpWord = new PhpWord();
+ $section = $phpWord->addSection();
+
+ // Test style array
+ $text = $section->addText('This is a test', [], ['line-height' => 2.0]);
+
+ $doc = TestHelperDOCX::getDocument($phpWord);
+ $element = $doc->getElement('/w:document/w:body/w:p/w:pPr/w:spacing');
+
+ $lineHeight = $element->getAttribute('w:line');
+ $lineRule = $element->getAttribute('w:lineRule');
+
+ self::assertEquals(480, $lineHeight);
+ self::assertEquals('auto', $lineRule);
+
+ // 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');
+
+ $lineHeight = $element->getAttribute('w:line');
+ $lineRule = $element->getAttribute('w:lineRule');
+
+ self::assertEquals(720, $lineHeight);
+ self::assertEquals('auto', $lineRule);
+ }
+
+ /**
+ * Test setLineHeight validation.
+ */
+ public function testLineHeightValidation(): void
+ {
+ $object = new Paragraph();
+ $object->setLineHeight('12.5pt');
+ self::assertEquals(12.5, $object->getLineHeight());
+ }
+
+ /**
+ * Test line height exception by using nonnumeric value.
+ */
+ public function testLineHeightException(): void
+ {
+ $this->expectException(\PhpOffice\PhpWord\Exception\InvalidStyleException::class);
+ $object = new Paragraph();
+ $object->setLineHeight('a');
+ }
+
+ public function testBidiVisual(): void
+ {
+ $object = new Paragraph();
+ self::assertNull($object->isBidi());
+ $object->setBidi(true);
+ self::assertTrue($object->isBidi());
+ $object->setBidi(false);
+ self::assertFalse($object->isBidi());
+ $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/PhpWord/Style/RowTest.php b/tests/PhpWordTests/Style/RowTest.php
similarity index 54%
rename from tests/PhpWord/Style/RowTest.php
rename to tests/PhpWordTests/Style/RowTest.php
index 534815b1b4..d3cc480ac7 100644
--- a/tests/PhpWord/Style/RowTest.php
+++ b/tests/PhpWordTests/Style/RowTest.php
@@ -1,4 +1,5 @@
true,
- 'cantSplit' => false,
+ $properties = [
+ 'tblHeader' => true,
+ 'cantSplit' => false,
'exactHeight' => true,
- );
+ ];
foreach ($properties as $key => $value) {
// set/get
$set = "set{$key}";
- $get = "get{$key}";
+ $get = "is{$key}";
$expected = $value ? 1 : 0;
$object->$set($value);
- $this->assertEquals($expected, $object->$get());
+ self::assertEquals($expected, $object->$get());
// setStyleValue
$value = !$value;
$expected = $value ? 1 : 0;
$object->setStyleValue("{$key}", $value);
- $this->assertEquals($expected, $object->$get());
- }
- }
-
- /**
- * Test properties with nonboolean values, which will return default value
- */
- public function testNonBooleanValue()
- {
- $object = new Row();
-
- $properties = array(
- 'tblHeader' => 'a',
- 'cantSplit' => 'b',
- 'exactHeight' => 'c',
- );
- foreach ($properties as $key => $value) {
- $set = "set{$key}";
- $get = "get{$key}";
- $object->$set($value);
- $this->assertFalse($object->$get());
+ self::assertEquals($expected, $object->$get());
}
}
}
diff --git a/tests/PhpWordTests/Style/SectionTest.php b/tests/PhpWordTests/Style/SectionTest.php
new file mode 100644
index 0000000000..e03dbb7596
--- /dev/null
+++ b/tests/PhpWordTests/Style/SectionTest.php
@@ -0,0 +1,350 @@
+getOrientation());
+ self::assertEqualsWithDelta(Section::DEFAULT_WIDTH, $oSettings->getPageSizeW(), 0.000000001);
+ self::assertEqualsWithDelta(Section::DEFAULT_HEIGHT, $oSettings->getPageSizeH(), 0.000000001);
+ self::assertEquals('A4', $oSettings->getPaperSize());
+
+ $oSettings->setSettingValue('orientation', 'landscape');
+ self::assertEquals('landscape', $oSettings->getOrientation());
+ self::assertEqualsWithDelta(Section::DEFAULT_HEIGHT, $oSettings->getPageSizeW(), 0.000000001);
+ self::assertEqualsWithDelta(Section::DEFAULT_WIDTH, $oSettings->getPageSizeH(), 0.000000001);
+
+ $iVal = mt_rand(1, 1000);
+ $oSettings->setSettingValue('borderSize', $iVal);
+ self::assertEquals([$iVal, $iVal, $iVal, $iVal], $oSettings->getBorderSize());
+ self::assertEquals($iVal, $oSettings->getBorderBottomSize());
+ self::assertEquals($iVal, $oSettings->getBorderLeftSize());
+ self::assertEquals($iVal, $oSettings->getBorderRightSize());
+ self::assertEquals($iVal, $oSettings->getBorderTopSize());
+
+ $oSettings->setSettingValue('borderColor', 'FF00AA');
+ self::assertEquals(['FF00AA', 'FF00AA', 'FF00AA', 'FF00AA'], $oSettings->getBorderColor());
+ self::assertEquals('FF00AA', $oSettings->getBorderBottomColor());
+ self::assertEquals('FF00AA', $oSettings->getBorderLeftColor());
+ self::assertEquals('FF00AA', $oSettings->getBorderRightColor());
+ self::assertEquals('FF00AA', $oSettings->getBorderTopColor());
+
+ $iVal = mt_rand(1, 1000);
+ $oSettings->setSettingValue('headerHeight', $iVal);
+ self::assertEquals($iVal, $oSettings->getHeaderHeight());
+
+ $oSettings->setSettingValue('lineNumbering', []);
+ $oSettings->setSettingValue(
+ 'lineNumbering',
+ [
+ 'start' => 1,
+ 'increment' => 1,
+ 'distance' => 240,
+ 'restart' => 'newPage',
+ ]
+ );
+ self::assertInstanceOf('PhpOffice\\PhpWord\\Style\\LineNumbering', $oSettings->getLineNumbering());
+
+ $oSettings->setSettingValue('lineNumbering', null);
+ self::assertNull($oSettings->getLineNumbering());
+ }
+
+ /**
+ * Set/get margin.
+ */
+ public function testMargin(): void
+ {
+ // Section Settings
+ $oSettings = new Section();
+
+ $iVal = mt_rand(1, 1000);
+ $oSettings->setMarginTop($iVal);
+ self::assertEquals($iVal, $oSettings->getMarginTop());
+
+ $iVal = mt_rand(1, 1000);
+ $oSettings->setMarginBottom($iVal);
+ self::assertEquals($iVal, $oSettings->getMarginBottom());
+
+ $iVal = mt_rand(1, 1000);
+ $oSettings->setMarginLeft($iVal);
+ self::assertEquals($iVal, $oSettings->getMarginLeft());
+
+ $iVal = mt_rand(1, 1000);
+ $oSettings->setMarginRight($iVal);
+ self::assertEquals($iVal, $oSettings->getMarginRight());
+ }
+
+ /**
+ * Set/get page width.
+ */
+ public function testPageWidth(): void
+ {
+ // Section Settings
+ $oSettings = new Section();
+
+ self::assertEqualsWithDelta(Section::DEFAULT_WIDTH, $oSettings->getPageSizeW(), 0.000000001);
+ $iVal = mt_rand(1, 1000);
+ $oSettings->setSettingValue('pageSizeW', $iVal);
+ self::assertEquals($iVal, $oSettings->getPageSizeW());
+ }
+
+ /**
+ * Set/get page height.
+ */
+ public function testPageHeight(): void
+ {
+ // Section Settings
+ $oSettings = new Section();
+
+ self::assertEqualsWithDelta(Section::DEFAULT_HEIGHT, $oSettings->getPageSizeH(), 0.000000001);
+ $iVal = mt_rand(1, 1000);
+ $oSettings->setSettingValue('pageSizeH', $iVal);
+ self::assertEquals($iVal, $oSettings->getPageSizeH());
+ }
+
+ /**
+ * Set/get landscape orientation.
+ */
+ public function testOrientationLandscape(): void
+ {
+ // Section Settings
+ $oSettings = new Section();
+
+ $oSettings->setLandscape();
+ self::assertEquals('landscape', $oSettings->getOrientation());
+ self::assertEqualsWithDelta(Section::DEFAULT_HEIGHT, $oSettings->getPageSizeW(), 0.000000001);
+ self::assertEqualsWithDelta(Section::DEFAULT_WIDTH, $oSettings->getPageSizeH(), 0.000000001);
+ }
+
+ /**
+ * Set/get portrait orientation.
+ */
+ public function testOrientationPortrait(): void
+ {
+ // Section Settings
+ $oSettings = new Section();
+
+ $oSettings->setPortrait();
+ self::assertEquals('portrait', $oSettings->getOrientation());
+ self::assertEqualsWithDelta(Section::DEFAULT_WIDTH, $oSettings->getPageSizeW(), 0.000000001);
+ self::assertEqualsWithDelta(Section::DEFAULT_HEIGHT, $oSettings->getPageSizeH(), 0.000000001);
+ }
+
+ /**
+ * Set/get border size.
+ */
+ public function testBorderSize(): void
+ {
+ // Section Settings
+ $oSettings = new Section();
+
+ $iVal = mt_rand(1, 1000);
+ $oSettings->setBorderSize($iVal);
+ self::assertEquals([$iVal, $iVal, $iVal, $iVal], $oSettings->getBorderSize());
+ self::assertEquals($iVal, $oSettings->getBorderBottomSize());
+ self::assertEquals($iVal, $oSettings->getBorderLeftSize());
+ self::assertEquals($iVal, $oSettings->getBorderRightSize());
+ self::assertEquals($iVal, $oSettings->getBorderTopSize());
+
+ $iVal = mt_rand(1, 1000);
+ $oSettings->setBorderBottomSize($iVal);
+ self::assertEquals($iVal, $oSettings->getBorderBottomSize());
+
+ $iVal = mt_rand(1, 1000);
+ $oSettings->setBorderLeftSize($iVal);
+ self::assertEquals($iVal, $oSettings->getBorderLeftSize());
+
+ $iVal = mt_rand(1, 1000);
+ $oSettings->setBorderRightSize($iVal);
+ self::assertEquals($iVal, $oSettings->getBorderRightSize());
+
+ $iVal = mt_rand(1, 1000);
+ $oSettings->setBorderTopSize($iVal);
+ self::assertEquals($iVal, $oSettings->getBorderTopSize());
+ }
+
+ /**
+ * Set/get border color.
+ */
+ public function testBorderColor(): void
+ {
+ // Section Settings
+ $oSettings = new Section();
+
+ $oSettings->setBorderColor('FF00AA');
+ self::assertEquals(['FF00AA', 'FF00AA', 'FF00AA', 'FF00AA'], $oSettings->getBorderColor());
+ self::assertEquals('FF00AA', $oSettings->getBorderBottomColor());
+ self::assertEquals('FF00AA', $oSettings->getBorderLeftColor());
+ self::assertEquals('FF00AA', $oSettings->getBorderRightColor());
+ self::assertEquals('FF00AA', $oSettings->getBorderTopColor());
+
+ $oSettings->setBorderBottomColor('BBCCDD');
+ self::assertEquals('BBCCDD', $oSettings->getBorderBottomColor());
+
+ $oSettings->setBorderLeftColor('CCDDEE');
+ self::assertEquals('CCDDEE', $oSettings->getBorderLeftColor());
+
+ $oSettings->setBorderRightColor('11EE22');
+ self::assertEquals('11EE22', $oSettings->getBorderRightColor());
+
+ $oSettings->setBorderTopColor('22FF33');
+ self::assertEquals('22FF33', $oSettings->getBorderTopColor());
+ }
+
+ /**
+ * Set/get page numbering start.
+ */
+ public function testNumberingStart(): void
+ {
+ // Section Settings
+ $oSettings = new Section();
+
+ self::assertNull($oSettings->getPageNumberingStart());
+
+ $iVal = mt_rand(1, 1000);
+ $oSettings->setPageNumberingStart($iVal);
+ self::assertEquals($iVal, $oSettings->getPageNumberingStart());
+
+ $oSettings->setPageNumberingStart();
+ self::assertNull($oSettings->getPageNumberingStart());
+ }
+
+ /**
+ * Set/get header height.
+ */
+ public function testHeader(): void
+ {
+ $oSettings = new Section();
+
+ self::assertEquals(720, $oSettings->getHeaderHeight());
+
+ $iVal = mt_rand(1, 1000);
+ $oSettings->setHeaderHeight($iVal);
+ self::assertEquals($iVal, $oSettings->getHeaderHeight());
+
+ $oSettings->setHeaderHeight();
+ self::assertEquals(720, $oSettings->getHeaderHeight());
+ }
+
+ /**
+ * Set/get footer height.
+ */
+ public function testFooter(): void
+ {
+ // Section Settings
+ $oSettings = new Section();
+
+ self::assertEquals(720, $oSettings->getFooterHeight());
+
+ $iVal = mt_rand(1, 1000);
+ $oSettings->setFooterHeight($iVal);
+ self::assertEquals($iVal, $oSettings->getFooterHeight());
+
+ $oSettings->setFooterHeight();
+ self::assertEquals(720, $oSettings->getFooterHeight());
+ }
+
+ /**
+ * Set/get column number.
+ */
+ public function testColumnsNum(): void
+ {
+ // Section Settings
+ $oSettings = new Section();
+
+ // Default
+ self::assertEquals(1, $oSettings->getColsNum());
+
+ // Null value
+ $oSettings->setColsNum();
+ self::assertEquals(1, $oSettings->getColsNum());
+
+ // Random value
+ $iVal = mt_rand(1, 1000);
+ $oSettings->setColsNum($iVal);
+ self::assertEquals($iVal, $oSettings->getColsNum());
+ }
+
+ /**
+ * Set/get column spacing.
+ */
+ public function testColumnsSpace(): void
+ {
+ // Section Settings
+ $oSettings = new Section();
+
+ // Default
+ self::assertEquals(720, $oSettings->getColsSpace());
+
+ $iVal = mt_rand(1, 1000);
+ self::assertInstanceOf('PhpOffice\\PhpWord\\Style\\Section', $oSettings->setColsSpace($iVal));
+ self::assertEquals($iVal, $oSettings->getColsSpace());
+
+ self::assertInstanceOf('PhpOffice\\PhpWord\\Style\\Section', $oSettings->setColsSpace());
+ self::assertEquals(720, $oSettings->getColsSpace());
+ }
+
+ /**
+ * Set/get break type.
+ */
+ public function testBreakType(): void
+ {
+ // Section Settings
+ $oSettings = new Section();
+
+ self::assertNull($oSettings->getBreakType());
+
+ $oSettings->setBreakType('continuous');
+ self::assertEquals('continuous', $oSettings->getBreakType());
+
+ $oSettings->setBreakType();
+ self::assertNull($oSettings->getBreakType());
+ }
+
+ /**
+ * Vertical page alignment.
+ */
+ public function testVerticalAlign(): void
+ {
+ // Section Settings
+ $oSettings = new Section();
+
+ self::assertNull($oSettings->getVAlign());
+
+ $oSettings->setVAlign(VerticalJc::BOTH);
+ self::assertEquals('both', $oSettings->getVAlign());
+ }
+}
diff --git a/tests/PhpWord/Style/ShadingTest.php b/tests/PhpWordTests/Style/ShadingTest.php
similarity index 63%
rename from tests/PhpWord/Style/ShadingTest.php
rename to tests/PhpWordTests/Style/ShadingTest.php
index 7aba03a122..a5fc7a89dd 100644
--- a/tests/PhpWord/Style/ShadingTest.php
+++ b/tests/PhpWordTests/Style/ShadingTest.php
@@ -1,4 +1,5 @@
array('clear', 'solid'),
- 'color' => array(null, 'FF0000'),
- 'fill' => array(null, 'FF0000'),
- );
+ $properties = [
+ 'pattern' => ['clear', 'solid'],
+ 'color' => [null, 'FF0000'],
+ 'fill' => [null, 'FF0000'],
+ ];
foreach ($properties as $property => $value) {
- list($default, $expected) = $value;
+ [$default, $expected] = $value;
$get = "get{$property}";
$set = "set{$property}";
- $this->assertEquals($default, $object->$get()); // Default value
+ self::assertEquals($default, $object->$get()); // Default value
$object->$set($expected);
- $this->assertEquals($expected, $object->$get()); // New value
+ self::assertEquals($expected, $object->$get()); // New value
}
}
}
diff --git a/tests/PhpWordTests/Style/SpacingTest.php b/tests/PhpWordTests/Style/SpacingTest.php
new file mode 100644
index 0000000000..351b9f1b54
--- /dev/null
+++ b/tests/PhpWordTests/Style/SpacingTest.php
@@ -0,0 +1,69 @@
+ [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) {
+ [$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
+ }
+ }
+}
diff --git a/tests/PhpWordTests/Style/TOCTest.php b/tests/PhpWordTests/Style/TOCTest.php
new file mode 100644
index 0000000000..039bc11340
--- /dev/null
+++ b/tests/PhpWordTests/Style/TOCTest.php
@@ -0,0 +1,66 @@
+ [9062, 10],
+ 'indent' => [200, 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 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}";
+
+ self::assertEquals($default, $object->$get()); // Default value
+
+ $object->$set($expected);
+
+ self::assertEquals($expected, $object->$get()); // New value
+ }
+ }
+}
diff --git a/tests/PhpWordTests/Style/TabTest.php b/tests/PhpWordTests/Style/TabTest.php
new file mode 100644
index 0000000000..43b9ff2c85
--- /dev/null
+++ b/tests/PhpWordTests/Style/TabTest.php
@@ -0,0 +1,72 @@
+ [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],
+ ] 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
+ }
+ }
+}
diff --git a/tests/PhpWordTests/Style/TablePositionTest.php b/tests/PhpWordTests/Style/TablePositionTest.php
new file mode 100644
index 0000000000..695bb3d297
--- /dev/null
+++ b/tests/PhpWordTests/Style/TablePositionTest.php
@@ -0,0 +1,83 @@
+ TablePosition::VANCHOR_PAGE, 'bottomFromText' => 20];
+
+ $object = new TablePosition($styleTable);
+ self::assertEquals(TablePosition::VANCHOR_PAGE, $object->getVertAnchor());
+ self::assertEquals(20, $object->getBottomFromText());
+ }
+
+ /**
+ * Test setting style with normal value.
+ */
+ public function testSetGetNormalInt(): void
+ {
+ $object = new TablePosition();
+
+ 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,
+ 'tblpYSpec' => TablePosition::YALIGN_OUTSIDE,
+ ] as $key => $value) {
+ $set = "set{$key}";
+ $get = "get{$key}";
+ $object->$set($value);
+ self::assertEquals($value, $object->$get());
+ }
+ }
+}
diff --git a/tests/PhpWordTests/Style/TableTest.php b/tests/PhpWordTests/Style/TableTest.php
new file mode 100644
index 0000000000..e53a51f5df
--- /dev/null
+++ b/tests/PhpWordTests/Style/TableTest.php
@@ -0,0 +1,255 @@
+ 'FF0000'];
+ $styleFirstRow = ['borderBottomSize' => 3];
+
+ $object = new Table($styleTable, $styleFirstRow);
+ self::assertEquals('FF0000', $object->getBgColor());
+
+ $firstRow = $object->getFirstRow();
+ self::assertInstanceOf('PhpOffice\\PhpWord\\Style\\Table', $firstRow);
+ self::assertEquals(3, $firstRow->getBorderBottomSize());
+ }
+
+ /**
+ * Test default values when passing no style.
+ */
+ public function testDefaultValues(): void
+ {
+ $object = new Table();
+
+ self::assertNull($object->getBgColor());
+ self::assertEquals(Table::LAYOUT_AUTO, $object->getLayout());
+ self::assertEquals(TblWidth::AUTO, $object->getUnit());
+ self::assertNull($object->getIndent());
+ }
+
+ /**
+ * Test setting style with normal value.
+ */
+ public function testSetGetNormal(): void
+ {
+ $object = new Table();
+
+ $attributes = [
+ 'bgColor' => 'FF0000',
+ 'borderTopSize' => 4,
+ 'borderTopColor' => 'FF0000',
+ 'borderLeftSize' => 4,
+ 'borderLeftColor' => 'FF0000',
+ 'borderRightSize' => 4,
+ 'borderRightColor' => 'FF0000',
+ 'borderBottomSize' => 4,
+ 'borderBottomColor' => 'FF0000',
+ 'borderInsideHSize' => 4,
+ 'borderInsideHColor' => 'FF0000',
+ 'borderInsideVSize' => 4,
+ 'borderInsideVColor' => 'FF0000',
+ 'cellMarginTop' => 240,
+ 'cellMarginLeft' => 240,
+ 'cellMarginRight' => 240,
+ 'cellMarginBottom' => 240,
+ 'alignment' => JcTable::CENTER,
+ 'width' => 100,
+ 'unit' => 'pct',
+ 'layout' => Table::LAYOUT_FIXED,
+ ];
+ foreach ($attributes as $key => $value) {
+ $set = "set{$key}";
+ $get = "get{$key}";
+ $object->$set($value);
+ self::assertEquals($value, $object->$get());
+ }
+ }
+
+ 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.
+ *
+ * Set border color and test if each part has the same color
+ * While looping, push values array to be asserted with getBorderColor
+ */
+ public function testBorderColor(): void
+ {
+ $object = new Table();
+ $parts = ['Top', 'Left', 'Right', 'Bottom', 'InsideH', 'InsideV'];
+
+ $value = 'FF0000';
+ $object->setBorderColor($value);
+ $values = [];
+ foreach ($parts as $part) {
+ $get = "getBorder{$part}Color";
+ $values[] = $value;
+ self::assertEquals($value, $object->$get());
+ }
+ self::assertEquals($values, $object->getBorderColor());
+ }
+
+ /**
+ * Test border size.
+ *
+ * Set border size and test if each part has the same size
+ * While looping, push values array to be asserted with getBorderSize
+ * Value is in eights of a point, i.e. 4 / 8 = .5pt
+ */
+ public function testBorderSize(): void
+ {
+ $object = new Table();
+ $parts = ['Top', 'Left', 'Right', 'Bottom', 'InsideH', 'InsideV'];
+
+ $value = 4;
+ $object->setBorderSize($value);
+ $values = [];
+ foreach ($parts as $part) {
+ $get = "getBorder{$part}Size";
+ $values[] = $value;
+ self::assertEquals($value, $object->$get());
+ }
+ self::assertEquals($values, $object->getBorderSize());
+ }
+
+ /**
+ * Test cell margin.
+ *
+ * Set cell margin and test if each part has the same margin
+ * While looping, push values array to be asserted with getCellMargin
+ * Value is in twips
+ */
+ public function testCellMargin(): void
+ {
+ $object = new Table();
+ $parts = ['Top', 'Left', 'Right', 'Bottom'];
+
+ $value = 240;
+ $object->setCellMargin($value);
+ $values = [];
+ foreach ($parts as $part) {
+ $get = "getCellMargin{$part}";
+ $values[] = $value;
+ self::assertEquals($value, $object->$get());
+ }
+ self::assertEquals($values, $object->getCellMargin());
+ self::assertTrue($object->hasMargin());
+ }
+
+ /**
+ * Set style value for various special value types.
+ */
+ public function testSetStyleValue(): void
+ {
+ $object = new Table();
+ $object->setStyleValue('borderSize', 120);
+ $object->setStyleValue('cellMargin', 240);
+ $object->setStyleValue('borderColor', '999999');
+
+ self::assertEquals([120, 120, 120, 120, 120, 120], $object->getBorderSize());
+ self::assertEquals([240, 240, 240, 240], $object->getCellMargin());
+ self::assertEquals(
+ ['999999', '999999', '999999', '999999', '999999', '999999'],
+ $object->getBorderColor()
+ );
+ }
+
+ /**
+ * Tests table cell spacing.
+ */
+ public function testTableCellSpacing(): void
+ {
+ $object = new Table();
+ self::assertNull($object->getCellSpacing());
+
+ $object = new Table(['cellSpacing' => 20]);
+ self::assertEquals(20, $object->getCellSpacing());
+ }
+
+ /**
+ * Tests table floating position.
+ */
+ public function testTablePosition(): void
+ {
+ $object = new Table();
+ self::assertNull($object->getPosition());
+
+ $object->setPosition(['vertAnchor' => TablePosition::VANCHOR_PAGE]);
+ self::assertNotNull($object->getPosition());
+ self::assertEquals(TablePosition::VANCHOR_PAGE, $object->getPosition()->getVertAnchor());
+ }
+
+ public function testIndent(): void
+ {
+ $indent = new TblWidthComplexType(100, TblWidth::TWIP);
+
+ $table = new Table(['indent' => $indent]);
+
+ self::assertSame($indent, $table->getIndent());
+ }
+}
diff --git a/tests/PhpWordTests/Style/TextBoxTest.php b/tests/PhpWordTests/Style/TextBoxTest.php
new file mode 100644
index 0000000000..30c01bd368
--- /dev/null
+++ b/tests/PhpWordTests/Style/TextBoxTest.php
@@ -0,0 +1,321 @@
+ 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',
+ ];
+ foreach ($properties as $key => $value) {
+ $set = "set{$key}";
+ $get = "get{$key}";
+ $object->$set($value);
+ self::assertEquals($value, $object->$get());
+ }
+ }
+
+ /**
+ * Test setStyleValue method.
+ */
+ 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',
+ 'innerMarginBottom' => '5',
+ 'innerMarginLeft' => '5',
+ 'borderSize' => '2',
+ 'borderColor' => 'red',
+ 'bgColor' => 'blue',
+ ];
+ foreach ($properties as $key => $value) {
+ $get = "get{$key}";
+ $object->setStyleValue("{$key}", $value);
+ self::assertEquals($value, $object->$get());
+ }
+ }
+
+ /**
+ * Test setWrappingStyle exception.
+ */
+ public function testSetWrappingStyleException(): void
+ {
+ $this->expectException(InvalidArgumentException::class);
+ $object = new TextBox();
+ $object->setWrappingStyle('foo');
+ }
+
+ /**
+ * Test set/get width.
+ */
+ public function testSetGetWidth(): void
+ {
+ $expected = 200;
+ $object = new TextBox();
+ $object->setWidth($expected);
+ self::assertEquals($expected, $object->getWidth());
+ }
+
+ /**
+ * Test set/get height.
+ */
+ public function testSetGetHeight(): void
+ {
+ $expected = 200;
+ $object = new TextBox();
+ $object->setHeight($expected);
+ self::assertEquals($expected, $object->getHeight());
+ }
+
+ /**
+ * Test set/get height.
+ */
+ public function testSetGetAlign(): void
+ {
+ $textBox = new TextBox();
+
+ $expectedAlignment = Jc::START;
+ $textBox->setAlignment($expectedAlignment);
+ self::assertEquals($expectedAlignment, $textBox->getAlignment());
+ }
+
+ /**
+ * Test set/get marginTop.
+ */
+ public function testSetGetMarginTop(): void
+ {
+ $expected = 5;
+ $object = new TextBox();
+ $object->setMarginTop($expected);
+ self::assertEquals($expected, $object->getMarginTop());
+ }
+
+ /**
+ * Test set/get marginLeft.
+ */
+ public function testSetGetMarginLeft(): void
+ {
+ $expected = 5;
+ $object = new TextBox();
+ $object->setMarginLeft($expected);
+ self::assertEquals($expected, $object->getMarginLeft());
+ }
+
+ /**
+ * Test set/get innerMarginTop.
+ */
+ public function testSetGetInnerMarginTop(): void
+ {
+ $expected = 5;
+ $object = new TextBox();
+ $object->setInnerMarginTop($expected);
+ self::assertEquals($expected, $object->getInnerMarginTop());
+ }
+
+ /**
+ * Test set/get wrappingStyle.
+ */
+ public function testSetGetWrappingStyle(): void
+ {
+ $expected = 'inline';
+ $object = new TextBox();
+ $object->setWrappingStyle($expected);
+ self::assertEquals($expected, $object->getWrappingStyle());
+ }
+
+ /**
+ * Test set/get positioning.
+ */
+ public function testSetGetPositioning(): void
+ {
+ $expected = 'absolute';
+ $object = new TextBox();
+ $object->setPositioning($expected);
+ self::assertEquals($expected, $object->getPositioning());
+ }
+
+ /**
+ * Test set/get posHorizontal.
+ */
+ public function testSetGetPosHorizontal(): void
+ {
+ $expected = 'center';
+ $object = new TextBox();
+ $object->setPosHorizontal($expected);
+ self::assertEquals($expected, $object->getPosHorizontal());
+ }
+
+ /**
+ * Test set/get posVertical.
+ */
+ public function testSetGetPosVertical(): void
+ {
+ $expected = 'top';
+ $object = new TextBox();
+ $object->setPosVertical($expected);
+ self::assertEquals($expected, $object->getPosVertical());
+ }
+
+ /**
+ * Test set/get posHorizontalRel.
+ */
+ public function testSetGetPosHorizontalRel(): void
+ {
+ $expected = 'margin';
+ $object = new TextBox();
+ $object->setPosHorizontalRel($expected);
+ self::assertEquals($expected, $object->getPosHorizontalRel());
+ }
+
+ /**
+ * Test set/get posVerticalRel.
+ */
+ public function testSetGetPosVerticalRel(): void
+ {
+ $expected = 'page';
+ $object = new TextBox();
+ $object->setPosVerticalRel($expected);
+ self::assertEquals($expected, $object->getPosVerticalRel());
+ }
+
+ /**
+ * Test set/get innerMarginRight.
+ */
+ public function testSetGetInnerMarginRight(): void
+ {
+ $expected = 5;
+ $object = new TextBox();
+ $object->setInnerMarginRight($expected);
+ self::assertEquals($expected, $object->getInnerMarginRight());
+ }
+
+ /**
+ * Test set/get innerMarginBottom.
+ */
+ public function testSetGetInnerMarginBottom(): void
+ {
+ $expected = 5;
+ $object = new TextBox();
+ $object->setInnerMarginBottom($expected);
+ self::assertEquals($expected, $object->getInnerMarginBottom());
+ }
+
+ /**
+ * Test set/get innerMarginLeft.
+ */
+ public function testSetGetInnerMarginLeft(): void
+ {
+ $expected = 5;
+ $object = new TextBox();
+ $object->setInnerMarginLeft($expected);
+ self::assertEquals($expected, $object->getInnerMarginLeft());
+ }
+
+ /**
+ * Test set/get innerMarginLeft.
+ */
+ public function testSetGetInnerMargin(): void
+ {
+ $expected = 5;
+ $object = new TextBox();
+ $object->setInnerMargin($expected);
+ self::assertEquals([$expected, $expected, $expected, $expected], $object->getInnerMargin());
+ }
+
+ /**
+ * Test set/get borderSize.
+ */
+ public function testSetGetBorderSize(): void
+ {
+ $expected = 2;
+ $object = new TextBox();
+ $object->setBorderSize($expected);
+ self::assertEquals($expected, $object->getBorderSize());
+ }
+
+ /**
+ * Test set/get borderColor.
+ */
+ public function testSetGetBorderColor(): void
+ {
+ $expected = 'red';
+ $object = new TextBox();
+ $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());
+ }
+}
diff --git a/tests/PhpWord/StyleTest.php b/tests/PhpWordTests/StyleTest.php
similarity index 54%
rename from tests/PhpWord/StyleTest.php
rename to tests/PhpWordTests/StyleTest.php
index cbc39c871e..6115e04426 100644
--- a/tests/PhpWord/StyleTest.php
+++ b/tests/PhpWordTests/StyleTest.php
@@ -1,4 +1,5 @@
Jc::CENTER);
- $font = array('italic' => true, '_bold' => true);
- $table = array('bgColor' => 'CCCCCC');
- $styles = array(
+ $paragraph = ['alignment' => Jc::CENTER];
+ $font = ['italic' => true, '_bold' => true];
+ $table = ['bgColor' => 'CCCCCC'];
+ $numbering = [
+ 'type' => 'multilevel',
+ 'levels' => [
+ [
+ 'start' => 1,
+ 'format' => 'decimal',
+ 'restart' => 1,
+ 'suffix' => 'space',
+ 'text' => '%1.',
+ 'alignment' => Jc::START,
+ ],
+ ],
+ ];
+
+ $styles = [
'Paragraph' => 'Paragraph',
- 'Font' => 'Font',
- 'Link' => 'Font',
- 'Table' => 'Table',
+ 'Font' => 'Font',
+ 'Link' => 'Font',
+ 'Table' => 'Table',
'Heading_1' => 'Font',
- 'Normal' => 'Paragraph',
- );
+ '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);
- $this->assertCount(count($styles), Style::getStyles());
+ self::assertCount(count($styles), Style::getStyles());
foreach ($styles as $name => $style) {
- $this->assertInstanceOf("PhpOffice\\PhpWord\\Style\\{$style}", Style::getStyle($name));
+ self::assertInstanceOf("PhpOffice\\PhpWord\\Style\\{$style}", Style::getStyle($name));
}
- $this->assertNull(Style::getStyle('Unknown'));
+ self::assertNull(Style::getStyle('Unknown'));
Style::resetStyles();
- $this->assertCount(0, Style::getStyles());
+ self::assertCount(0, Style::getStyles());
}
/**
- * Test default paragraph style
+ * Test default paragraph style.
*
* @covers ::setDefaultParagraphStyle
- * @test
*/
- public function testDefaultParagraphStyle()
+ public function testDefaultParagraphStyle(): void
{
- $paragraph = array('alignment' => Jc::CENTER);
+ $paragraph = ['alignment' => Jc::CENTER];
Style::setDefaultParagraphStyle($paragraph);
- $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Paragraph', Style::getStyle('Normal'));
+ self::assertInstanceOf('PhpOffice\\PhpWord\\Style\\Paragraph', Style::getStyle('Normal'));
}
}
diff --git a/tests/PhpWordTests/TemplateProcessorTest.php b/tests/PhpWordTests/TemplateProcessorTest.php
new file mode 100644
index 0000000000..8ae4dfa59a
--- /dev/null
+++ b/tests/PhpWordTests/TemplateProcessorTest.php
@@ -0,0 +1,1781 @@
+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
+ * @covers \PhpOffice\PhpWord\Shared\ZipArchive::close
+ */
+ public function testTheConstruct(): void
+ {
+ $object = $this->getTemplateProcessor(__DIR__ . '/_files/templates/blank.docx');
+ self::assertEquals([], $object->getVariables());
+ $object->save();
+
+ try {
+ $object->zip()->close();
+ self::fail('Expected exception for double close');
+ } catch (Throwable $e) {
+ // nothing to do here
+ }
+ }
+
+ /**
+ * Template can be saved in temporary location.
+ *
+ * @covers ::save
+ * @covers ::zip
+ */
+ public function xtestTemplateCanBeSavedInTemporaryLocation(string $templateFqfn, TemplateProcessor $templateProcessor): string
+ {
+ $xslDomDocument = new DOMDocument();
+ $xslDomDocument->load(__DIR__ . '/_files/xsl/remove_tables_by_needle.xsl');
+ foreach (['${employee.', '${scoreboard.', '${reference.'] as $needle) {
+ $templateProcessor->applyXslStyleSheet($xslDomDocument, ['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();
+
+ self::assertNotEmpty($documentFqfn, 'FQFN of the saved document is empty.');
+ self::assertFileExists($documentFqfn, "The saved document \"{$documentFqfn}\" doesn't exist.");
+
+ $templateZip = new ZipArchive();
+ $templateZip->open($templateFqfn);
+ $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);
+ $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}\".");
+ }
+
+ self::assertNotEquals($templateHeaderXml, $documentHeaderXml);
+ self::assertNotEquals($templateMainPartXml, $documentMainPartXml);
+ self::assertNotEquals($templateFooterXml, $documentFooterXml);
+ self::assertEquals($embeddingText, $documentEmbedding);
+
+ return $documentFqfn;
+ }
+
+ /**
+ * XSL stylesheet can be applied.
+ *
+ * @covers ::applyXslStyleSheet
+ */
+ public function testXslStyleSheetCanBeApplied(): void
+ {
+ $templateFqfn = __DIR__ . '/_files/templates/with_table_macros.docx';
+ $templateProcessor = $this->getTemplateProcessor($templateFqfn);
+
+ $actualDocumentFqfn = $this->xtestTemplateCanBeSavedInTemporaryLocation($templateFqfn, $templateProcessor);
+ $expectedDocumentFqfn = __DIR__ . '/_files/documents/without_table_macros.docx';
+
+ $actualDocumentZip = new ZipArchive();
+ $actualDocumentZip->open($actualDocumentFqfn);
+ $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);
+ $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}\".");
+ }
+
+ self::assertSame($expectedHeaderXml, $actualHeaderXml);
+ self::assertSame($expectedMainPartXml, $actualMainPartXml);
+ self::assertSame($expectedFooterXml, $actualFooterXml);
+ }
+
+ /**
+ * XSL stylesheet cannot be applied on failure in setting parameter value.
+ *
+ * @covers ::applyXslStyleSheet
+ */
+ public function testXslStyleSheetCanNotBeAppliedOnFailureOfSettingParameterValue(): void
+ {
+ if (\PHP_VERSION_ID >= 80000) {
+ // 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 = $this->getTemplateProcessor(__DIR__ . '/_files/templates/blank.docx');
+
+ $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, [1 => 'somevalue']);
+ }
+
+ /**
+ * XSL stylesheet can be applied on failure of loading XML from template.
+ *
+ * @covers ::applyXslStyleSheet
+ */
+ public function testXslStyleSheetCanNotBeAppliedOnFailureOfLoadingXmlFromTemplate(): void
+ {
+ $this->expectException(\PhpOffice\PhpWord\Exception\Exception::class);
+ $this->expectExceptionMessage('Could not load the given XML document.');
+ $templateProcessor = $this->getTemplateProcessor(__DIR__ . '/_files/templates/corrupted_main_document_part.docx');
+
+ $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);
+ }
+
+ /**
+ * @covers ::deleteRow
+ * @covers ::getVariables
+ * @covers ::saveAs
+ */
+ public function testDeleteRow(): void
+ {
+ $templateProcessor = $this->getTemplateProcessor(__DIR__ . '/_files/templates/delete-row.docx');
+
+ self::assertEquals(
+ ['deleteMe', 'deleteMeToo'],
+ $templateProcessor->getVariables()
+ );
+
+ $docName = 'delete-row-test-result.docx';
+ $templateProcessor->deleteRow('deleteMe');
+ self::assertEquals(
+ [],
+ $templateProcessor->getVariables()
+ );
+ $templateProcessor->saveAs($docName);
+ $docFound = file_exists($docName);
+ unlink($docName);
+ self::assertTrue($docFound);
+ }
+
+ /**
+ * @covers ::cloneRow
+ * @covers ::saveAs
+ * @covers ::setValue
+ */
+ public function testCloneRow(): void
+ {
+ $templateProcessor = $this->getTemplateProcessor(__DIR__ . '/_files/templates/clone-merge.docx');
+
+ self::assertEquals(
+ ['tableHeader', 'userId', 'userName', 'userLocation'],
+ $templateProcessor->getVariables()
+ );
+
+ $docName = 'clone-test-result.docx';
+ $templateProcessor->setValue('tableHeader', 'ééé');
+ $templateProcessor->cloneRow('userId', 1);
+ $templateProcessor->setValue('userId#1', 'Test');
+ $templateProcessor->saveAs($docName);
+ $docFound = file_exists($docName);
+ unlink($docName);
+ self::assertTrue($docFound);
+ }
+
+ /**
+ * @covers ::cloneRow
+ * @covers ::saveAs
+ * @covers ::setValue
+ */
+ public function testCloneRowWithCustomMacro(): void
+ {
+ $templateProcessor = $this->getTemplateProcessor(__DIR__ . '/_files/templates/clone-merge-with-custom-macro.docx');
+
+ $templateProcessor->setMacroOpeningChars('{#');
+ $templateProcessor->setMacroClosingChars('#}');
+
+ self::assertEquals(
+ ['tableHeader', 'userId', 'userName', 'userLocation'],
+ $templateProcessor->getVariables()
+ );
+
+ $docName = 'clone-test-result.docx';
+ $templateProcessor->setValue('tableHeader', 'ééé');
+ $templateProcessor->cloneRow('userId', 1);
+ $templateProcessor->setValue('userId#1', 'Test');
+ $templateProcessor->saveAs($docName);
+ $docFound = file_exists($docName);
+ unlink($docName);
+ self::assertTrue($docFound);
+ }
+
+ /**
+ * @covers ::cloneRow
+ * @covers ::saveAs
+ * @covers ::setValue
+ */
+ public function testCloneRowAndSetValues(): void
+ {
+ $mainPart = '
+
+
+
+
+
+
+
+ ${userId}
+
+
+
+
+
+
+ ${userName}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ${userLocation}
+
+
+
+
+ ';
+ $templateProcessor = new TestableTemplateProcesor($mainPart);
+
+ self::assertEquals(
+ ['userId', 'userName', 'userLocation'],
+ $templateProcessor->getVariables()
+ );
+
+ $values = [
+ ['userId' => 1, 'userName' => 'Batman', 'userLocation' => 'Gotham City'],
+ ['userId' => 2, 'userName' => 'Superman', 'userLocation' => 'Metropolis'],
+ ];
+ $templateProcessor->setValue('tableHeader', 'My clonable table');
+ $templateProcessor->cloneRowAndSetValues('userId', $values);
+ self::assertStringContainsString('Superman ', $templateProcessor->getMainPart());
+ self::assertStringContainsString('Metropolis ', $templateProcessor->getMainPart());
+ }
+
+ public function testCloneNotExistingRowShouldThrowException(): void
+ {
+ $this->expectException(Exception::class);
+ $mainPart = 'text ';
+ $templateProcessor = new TestableTemplateProcesor($mainPart);
+
+ $templateProcessor->cloneRow('fake_search', 2);
+ }
+
+ /**
+ * @covers ::cloneRow
+ * @covers ::saveAs
+ * @covers ::setValue
+ */
+ public function testCloneRowAndSetValuesWithCustomMacro(): void
+ {
+ $mainPart = '
+
+
+
+
+
+
+
+ {{userId}}
+
+
+
+
+
+
+ {{userName}}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{userLocation}}
+
+
+
+
+ ';
+ $templateProcessor = new TestableTemplateProcesor($mainPart);
+ $templateProcessor->setMacroOpeningChars('{{');
+ $templateProcessor->setMacroClosingChars('}}');
+
+ self::assertEquals(
+ ['userId', 'userName', 'userLocation'],
+ $templateProcessor->getVariables()
+ );
+
+ $values = [
+ ['userId' => 1, 'userName' => 'Batman', 'userLocation' => 'Gotham City'],
+ ['userId' => 2, 'userName' => 'Superman', 'userLocation' => 'Metropolis'],
+ ];
+ $templateProcessor->setValue('tableHeader', 'My clonable table');
+ $templateProcessor->cloneRowAndSetValues('userId', $values);
+ self::assertStringContainsString('Superman ', $templateProcessor->getMainPart());
+ self::assertStringContainsString('Metropolis ', $templateProcessor->getMainPart());
+ }
+
+ /**
+ * @covers ::saveAs
+ * @covers ::setValue
+ */
+ public function testMacrosCanBeReplacedInHeaderAndFooter(): void
+ {
+ $templateProcessor = $this->getTemplateProcessor(__DIR__ . '/_files/templates/header-footer.docx');
+
+ self::assertEquals(['documentContent', 'headerValue:100:100', 'footerValue'], $templateProcessor->getVariables());
+
+ $macroNames = ['headerValue', 'documentContent', 'footerValue'];
+ $macroValues = ['Header Value', 'Document text.', 'Footer Value'];
+ $templateProcessor->setValue($macroNames, $macroValues);
+
+ $docName = 'header-footer-test-result.docx';
+ $templateProcessor->saveAs($docName);
+ $docFound = file_exists($docName);
+ unlink($docName);
+ self::assertTrue($docFound);
+ }
+
+ /**
+ * @covers ::saveAs
+ * @covers ::setValue
+ */
+ public function testCustomMacrosCanBeReplacedInHeaderAndFooter(): void
+ {
+ $templateProcessor = $this->getTemplateProcessor(__DIR__ . '/_files/templates/header-footer-with-custom-macro.docx');
+ $templateProcessor->setMacroOpeningChars('{{');
+ $templateProcessor->setMacroClosingChars('}}');
+
+ self::assertEquals(['documentContent', 'headerValue:100:100', 'footerValue'], $templateProcessor->getVariables());
+
+ $macroNames = ['headerValue', 'documentContent', 'footerValue'];
+ $macroValues = ['Header Value', 'Document text.', 'Footer Value'];
+ $templateProcessor->setValue($macroNames, $macroValues);
+
+ $docName = 'header-footer-test-result.docx';
+ $templateProcessor->saveAs($docName);
+ $docFound = file_exists($docName);
+ unlink($docName);
+ self::assertTrue($docFound);
+ }
+
+ /**
+ * @covers ::setValue
+ */
+ public function testSetValue(): void
+ {
+ $templateProcessor = $this->getTemplateProcessor(__DIR__ . '/_files/templates/clone-merge.docx');
+ Settings::setOutputEscapingEnabled(true);
+ $helloworld = "hello\nworld";
+ $templateProcessor->setValue('userName', $helloworld);
+ self::assertEquals(
+ ['tableHeader', 'userId', 'userLocation'],
+ $templateProcessor->getVariables()
+ );
+ }
+
+ /**
+ * @covers ::setValue
+ */
+ public function testSetValueWithCustomMacro(): void
+ {
+ $templateProcessor = $this->getTemplateProcessor(__DIR__ . '/_files/templates/clone-merge-with-custom-macro.docx');
+ $templateProcessor->setMacroChars('{#', '#}');
+ Settings::setOutputEscapingEnabled(true);
+ $helloworld = "hello\nworld";
+ $templateProcessor->setValue('userName', $helloworld);
+ self::assertEquals(
+ ['tableHeader', 'userId', 'userLocation'],
+ $templateProcessor->getVariables()
+ );
+ }
+
+ public function testSetComplexValue(): void
+ {
+ $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);
+
+ self::assertEquals(preg_replace('/>\s+', '><', $result), preg_replace('/>\s+', '><', $templateProcessor->getMainPart()));
+ }
+
+ public function testSetComplexValueWithCustomMacro(): void
+ {
+ $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->setMacroChars('{{', '}}');
+ $templateProcessor->setComplexBlock('document-title', $title);
+ $templateProcessor->setComplexValue('firstname', $firstname);
+ $templateProcessor->setComplexValue('lastname', $lastname);
+
+ self::assertEquals(preg_replace('/>\s+', '><', $result), preg_replace('/>\s+', '><', $templateProcessor->getMainPart()));
+ }
+
+ /**
+ * @covers ::setValues
+ */
+ public function testSetValues(): void
+ {
+ $mainPart = '
+
+
+ Hello ${firstname} ${lastname}
+
+
+
+
+ Hello ${firstname} ${lastname}
+
+
+
+
+ Hello ${firstname} ${lastname}
+
+
+ ';
+
+ $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']);
+ }
+
+ /**
+ * @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
+ */
+ public function testSetValuesWithCustomMacro(): void
+ {
+ $mainPart = '
+
+
+ Hello {#firstname#} {#lastname#}
+
+ ';
+
+ $templateProcessor = new TestableTemplateProcesor($mainPart);
+ $templateProcessor->setMacroChars('{#', '#}');
+ $templateProcessor->setValues(['firstname' => 'John', 'lastname' => 'Doe']);
+
+ 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
+ */
+ public function testSetImageValue(): void
+ {
+ $templateProcessor = $this->getTemplateProcessor(__DIR__ . '/_files/templates/header-footer.docx');
+ $imagePath = __DIR__ . '/_files/images/earth.jpg';
+
+ $variablesReplace = [
+ 'headerValue' => function () use ($imagePath) {
+ return $imagePath;
+ },
+ 'documentContent' => ['path' => $imagePath, 'width' => 500, 'height' => 500],
+ 'footerValue' => ['path' => $imagePath, 'width' => 100, 'height' => 50, 'ratio' => false],
+ ];
+ $templateProcessor->setImageValue(array_keys($variablesReplace), $variablesReplace);
+
+ $docName = 'header-footer-images-test-result.docx';
+ $templateProcessor->saveAs($docName);
+
+ self::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}\".");
+ }
+
+ self::assertNotEmpty($expectedImage, 'Embed image doesn\'t found.');
+ self::assertStringContainsString('/word/media/image_rId11_document.jpeg', $expectedContentTypesXml, '[Content_Types].xml missed "/word/media/image5_document.jpeg"');
+ self::assertStringContainsString('/word/_rels/header1.xml.rels', $expectedContentTypesXml, '[Content_Types].xml missed "/word/_rels/header1.xml.rels"');
+ self::assertStringContainsString('/word/_rels/footer1.xml.rels', $expectedContentTypesXml, '[Content_Types].xml missed "/word/_rels/footer1.xml.rels"');
+ self::assertStringNotContainsString('${documentContent}', $expectedMainPartXml, 'word/document.xml has no image.');
+ self::assertStringNotContainsString('${headerValue}', $expectedHeaderPartXml, 'word/header1.xml has no image.');
+ self::assertStringNotContainsString('${footerValue}', $expectedFooterPartXml, 'word/footer1.xml has no image.');
+ self::assertStringContainsString('media/image_rId11_document.jpeg', $expectedDocumentRelationsXml, 'word/_rels/document.xml.rels missed "media/image5_document.jpeg"');
+ self::assertStringContainsString('media/image_rId11_document.jpeg', $expectedHeaderRelationsXml, 'word/_rels/header1.xml.rels missed "media/image5_document.jpeg"');
+ self::assertStringContainsString('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 PhpWord();
+ $section = $phpWord->addSection();
+ $section->addText('${Test:width=100:ratio=true}');
+ $objWriter = IOFactory::createWriter($phpWord, 'Word2007');
+ $objWriter->save($testFileName);
+ self::assertFileExists($testFileName, "Generated file '{$testFileName}' not found!");
+
+ $resultFileName = 'images-test-result.docx';
+ $templateProcessor = new TemplateProcessor($testFileName);
+ unlink($testFileName);
+ $templateProcessor->setImageValue('Test', $imagePath);
+ $templateProcessor->setImageValue('Test1', $imagePath);
+ $templateProcessor->setImageValue('Test2', $imagePath);
+ $templateProcessor->saveAs($resultFileName);
+ self::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);
+
+ self::assertStringNotContainsString('${Test}', $expectedMainPartXml, 'word/document.xml has no image.');
+ }
+
+ /**
+ * @covers ::cloneBlock
+ * @covers ::deleteBlock
+ * @covers ::saveAs
+ */
+ public function testCloneDeleteBlock(): void
+ {
+ $templateProcessor = $this->getTemplateProcessor(__DIR__ . '/_files/templates/clone-delete-block.docx');
+
+ self::assertEquals(
+ ['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);
+ self::assertTrue($docFound);
+ }
+
+ /**
+ * @covers ::getVariableCount
+ */
+ public function testGetVariableCountCountsHowManyTimesEachPlaceholderIsPresent(): void
+ {
+ // 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);
+
+ $templateProcessor = $this->getTemplateProcessor($templatePath);
+ $variableCount = $templateProcessor->getVariableCount();
+ unlink($templatePath);
+
+ self::assertEquals(
+ [
+ 'a_field_that_is_present_three_times' => 3,
+ 'a_field_that_is_present_twice' => 2,
+ 'a_field_that_is_present_one_time' => 1,
+ ],
+ $variableCount
+ );
+ }
+
+ /**
+ * @covers ::getVariableCount
+ */
+ public function testGetVariableCountCountsHowManyTimesEachPlaceholderIsPresentWithCustomMacro(): void
+ {
+ // 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);
+
+ $templateProcessor = $this->getTemplateProcessor($templatePath);
+ $templateProcessor->setMacroChars('{{', '}}');
+ $variableCount = $templateProcessor->getVariableCount();
+ unlink($templatePath);
+
+ self::assertEquals(
+ [
+ 'a_field_that_is_present_three_times' => 3,
+ 'a_field_that_is_present_twice' => 2,
+ 'a_field_that_is_present_one_time' => 1,
+ ],
+ $variableCount
+ );
+ }
+
+ /**
+ * @covers ::cloneBlock
+ */
+ public function testCloneBlockCanCloneABlockTwice(): void
+ {
+ // create template with placeholders and block
+ $phpWord = new PhpWord();
+ $section = $phpWord->addSection();
+ $documentElements = [
+ '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 = $this->getTemplateProcessor($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();
+ /** @var TextRun[] $actualElements */
+ $actualElements = $sections[0]->getElements();
+ unlink($templatePath);
+ $expectedElements = [
+ 'Title: Some title',
+ '123: Some text. ',
+ '456: Some other text. ',
+ ];
+ self::assertCount(count($expectedElements), $actualElements);
+ foreach ($expectedElements as $i => $expectedElement) {
+ self::assertEquals(
+ $expectedElement,
+ $actualElements[$i]->getElement(0)->getText()
+ );
+ }
+ }
+
+ /**
+ * @covers ::cloneBlock
+ */
+ public function testCloneBlockCanCloneABlockTwiceWithCustomMacro(): void
+ {
+ // create template with placeholders and block
+ $phpWord = new PhpWord();
+ $section = $phpWord->addSection();
+ $documentElements = [
+ '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 = $this->getTemplateProcessor($templatePath);
+ $templateProcessor->setMacroChars('{{', '}}');
+ $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();
+ /** @var TextRun[] $actualElements */
+ $actualElements = $sections[0]->getElements();
+
+ unlink($templatePath);
+ $expectedElements = [
+ 'Title: Some title',
+ '123: Some text. ',
+ '456: Some other text. ',
+ ];
+ self::assertCount(count($expectedElements), $actualElements);
+ foreach ($expectedElements as $i => $expectedElement) {
+ self::assertEquals(
+ $expectedElement,
+ $actualElements[$i]->getElement(0)->getText()
+ );
+ }
+ }
+
+ /**
+ * @covers ::cloneBlock
+ */
+ public function testCloneBlock(): void
+ {
+ $mainPart = '
+
+
+
+ ${CLONEME}
+
+
+
+
+ This block will be cloned with ${variable}
+
+
+
+
+ ${/CLONEME}
+
+ ';
+
+ $templateProcessor = new TestableTemplateProcesor($mainPart);
+ $templateProcessor->cloneBlock('CLONEME', 3);
+
+ self::assertEquals(3, substr_count($templateProcessor->getMainPart(), 'This block will be cloned with ${variable}'));
+ }
+
+ /**
+ * @covers ::cloneBlock
+ */
+ public function testCloneBlockWithCustomMacro(): void
+ {
+ $mainPart = '
+
+
+
+ {{CLONEME}}
+
+
+
+
+ This block will be cloned with {{variable}}
+
+
+
+
+ {{/CLONEME}}
+
+ ';
+
+ $templateProcessor = new TestableTemplateProcesor($mainPart);
+ $templateProcessor->setMacroChars('{{', '}}');
+ $templateProcessor->cloneBlock('CLONEME', 3);
+
+ self::assertEquals(3, substr_count($templateProcessor->getMainPart(), 'This block will be cloned with {{variable}}'));
+ }
+
+ /**
+ * @covers ::cloneBlock
+ */
+ public function testCloneBlockWithVariables(): void
+ {
+ $mainPart = '
+
+
+
+ ${CLONEME}
+
+
+
+
+ Address ${address}, Street ${street}
+
+
+
+
+ ${/CLONEME}
+
+ ';
+
+ $templateProcessor = new TestableTemplateProcesor($mainPart);
+ $templateProcessor->cloneBlock('CLONEME', 3, true, true);
+
+ self::assertStringContainsString('Address ${address#1}, Street ${street#1}', $templateProcessor->getMainPart());
+ self::assertStringContainsString('Address ${address#2}, Street ${street#2}', $templateProcessor->getMainPart());
+ self::assertStringContainsString('Address ${address#3}, Street ${street#3}', $templateProcessor->getMainPart());
+ }
+
+ /**
+ * @covers ::cloneBlock
+ */
+ public function testCloneBlockWithVariablesAndCustomMacro(): void
+ {
+ $mainPart = '
+
+
+
+ {{CLONEME}}
+
+
+
+
+ Address {{address}}, Street {{street}}
+
+
+
+
+ {{/CLONEME}}
+
+ ';
+
+ $templateProcessor = new TestableTemplateProcesor($mainPart);
+ $templateProcessor->setMacroChars('{{', '}}');
+ $templateProcessor->cloneBlock('CLONEME', 3, true, true);
+
+ self::assertStringContainsString('Address {{address#1}}, Street {{street#1}}', $templateProcessor->getMainPart());
+ self::assertStringContainsString('Address {{address#2}}, Street {{street#2}}', $templateProcessor->getMainPart());
+ self::assertStringContainsString('Address {{address#3}}, Street {{street#3}}', $templateProcessor->getMainPart());
+ }
+
+ public function testCloneBlockWithVariableReplacements(): void
+ {
+ $mainPart = '
+
+
+
+ ${CLONEME}
+
+
+
+
+ City: ${city}, Street: ${street}
+
+
+
+
+ ${/CLONEME}
+
+ ';
+
+ $replacements = [
+ ['city' => 'London', 'street' => 'Baker Street'],
+ ['city' => 'New York', 'street' => '5th Avenue'],
+ ['city' => 'Rome', 'street' => 'Via della Conciliazione'],
+ ];
+ $templateProcessor = new TestableTemplateProcesor($mainPart);
+ $templateProcessor->cloneBlock('CLONEME', 0, true, false, $replacements);
+
+ self::assertStringContainsString('City: London, Street: Baker Street', $templateProcessor->getMainPart());
+ self::assertStringContainsString('City: New York, Street: 5th Avenue', $templateProcessor->getMainPart());
+ self::assertStringContainsString('City: Rome, Street: Via della Conciliazione', $templateProcessor->getMainPart());
+ }
+
+ public function testCloneBlockWithVariableReplacementsAndCustomMacro(): void
+ {
+ $mainPart = '
+
+
+
+ {{CLONEME}}
+
+
+
+
+ City: {{city}}, Street: {{street}}
+
+
+
+
+ {{/CLONEME}}
+
+ ';
+
+ $replacements = [
+ ['city' => 'London', 'street' => 'Baker Street'],
+ ['city' => 'New York', 'street' => '5th Avenue'],
+ ['city' => 'Rome', 'street' => 'Via della Conciliazione'],
+ ];
+ $templateProcessor = new TestableTemplateProcesor($mainPart);
+ $templateProcessor->setMacroChars('{{', '}}');
+ $templateProcessor->cloneBlock('CLONEME', 0, true, false, $replacements);
+
+ self::assertStringContainsString('City: London, Street: Baker Street', $templateProcessor->getMainPart());
+ self::assertStringContainsString('City: New York, Street: 5th Avenue', $templateProcessor->getMainPart());
+ self::assertStringContainsString('City: Rome, Street: Via della Conciliazione', $templateProcessor->getMainPart());
+ }
+
+ /**
+ * Template macros can be fixed.
+ *
+ * @covers ::fixBrokenMacros
+ */
+ public function testFixBrokenMacros(): void
+ {
+ $templateProcessor = new TestableTemplateProcesor();
+
+ $fixed = $templateProcessor->fixBrokenMacros('normal text ');
+ self::assertEquals('normal text ', $fixed);
+
+ $fixed = $templateProcessor->fixBrokenMacros('${documentContent} ');
+ self::assertEquals('${documentContent} ', $fixed);
+
+ $fixed = $templateProcessor->fixBrokenMacros('$ {documentContent} ');
+ self::assertEquals('${documentContent} ', $fixed);
+
+ $fixed = $templateProcessor->fixBrokenMacros('$1500 ${documentContent} ');
+ self::assertEquals('$1500 ${documentContent} ', $fixed);
+
+ $fixed = $templateProcessor->fixBrokenMacros('$1500 $ {documentContent} ');
+ self::assertEquals('$1500 ${documentContent} ', $fixed);
+
+ $fixed = $templateProcessor->fixBrokenMacros('25$ plus some info {hint} ');
+ self::assertEquals('25$ plus some info {hint} ', $fixed);
+
+ $fixed = $templateProcessor->fixBrokenMacros('$ 15,000.00. $ { variable_name } ');
+ self::assertEquals('$ 15,000.00. ${variable_name} ', $fixed);
+ }
+
+ /**
+ * Template macros can be fixed even with cutome macro.
+ *
+ * @covers ::fixBrokenMacros
+ */
+ public function testFixBrokenMacrosWithCustomMacro(): void
+ {
+ $templateProcessor = new TestableTemplateProcesor();
+ $templateProcessor->setMacroChars('{{', '}}');
+
+ $fixed = $templateProcessor->fixBrokenMacros('normal text ');
+ self::assertEquals('normal text ', $fixed);
+
+ $fixed = $templateProcessor->fixBrokenMacros('{{documentContent}} ');
+ self::assertEquals('{{documentContent}} ', $fixed);
+
+ $fixed = $templateProcessor->fixBrokenMacros('{ {documentContent}} ');
+ self::assertEquals('{{documentContent}} ', $fixed);
+
+ $fixed = $templateProcessor->fixBrokenMacros('$1500 {{documentContent}} ');
+ self::assertEquals('$1500 {{documentContent}} ', $fixed);
+
+ $fixed = $templateProcessor->fixBrokenMacros('$1500 { {documentContent}} ');
+ self::assertEquals('$1500 {{documentContent}} ', $fixed);
+
+ $fixed = $templateProcessor->fixBrokenMacros('25$ plus some info {hint} ');
+ self::assertEquals('25$ plus some info {hint} ', $fixed);
+
+ $fixed = $templateProcessor->fixBrokenMacros('$ 15,000.00. { { variable_name }} ');
+ self::assertEquals('$ 15,000.00. {{variable_name}} ', $fixed);
+ }
+
+ /**
+ * @covers ::getMainPartName
+ */
+ public function testMainPartNameDetection(): void
+ {
+ $templateProcessor = $this->getTemplateProcessor(__DIR__ . '/_files/templates/document22-xml.docx');
+
+ $variables = ['test'];
+
+ self::assertEquals($variables, $templateProcessor->getVariables());
+ }
+
+ /**
+ * @covers ::getMainPartName
+ */
+ public function testMainPartNameDetectionWithCustomMacro(): void
+ {
+ $templateProcessor = $this->getTemplateProcessor(__DIR__ . '/_files/templates/document22-with-custom-macro-xml.docx');
+ $templateProcessor->setMacroOpeningChars('{#');
+ $templateProcessor->setMacroClosingChars('#}');
+ $variables = ['test'];
+
+ self::assertEquals($variables, $templateProcessor->getVariables());
+ }
+
+ /**
+ * @covers ::getVariables
+ */
+ public function testGetVariables(): void
+ {
+ $templateProcessor = new TestableTemplateProcesor();
+
+ $variables = $templateProcessor->getVariablesForPart('normal text ');
+ self::assertEquals([], $variables);
+
+ $variables = $templateProcessor->getVariablesForPart('${documentContent} ');
+ self::assertEquals(['documentContent'], $variables);
+
+ $variables = $templateProcessor->getVariablesForPart('$ 15,000.00. $ { variable_name } ');
+ self::assertEquals(['variable_name'], $variables);
+ }
+
+ /**
+ * @covers ::getVariables
+ */
+ public function testGetVariablesWithCustomMacro(): void
+ {
+ $templateProcessor = new TestableTemplateProcesor();
+ $templateProcessor->setMacroOpeningChars('{{');
+ $templateProcessor->setMacroClosingChars('}}');
+
+ $variables = $templateProcessor->getVariablesForPart('normal text ');
+ self::assertEquals([], $variables);
+
+ $variables = $templateProcessor->getVariablesForPart('{{documentContent}} ');
+ self::assertEquals(['documentContent'], $variables);
+
+ $variables = $templateProcessor->getVariablesForPart('{ 15,000.00. { { variable_name }} ');
+ self::assertEquals(['variable_name'], $variables);
+ }
+
+ /**
+ * @covers ::textNeedsSplitting
+ */
+ public function testTextNeedsSplitting(): void
+ {
+ $templateProcessor = new TestableTemplateProcesor();
+
+ self::assertFalse($templateProcessor->textNeedsSplitting('${nothing-to-replace} '));
+
+ $text = 'Hello ${firstname} ${lastname} ';
+ self::assertTrue($templateProcessor->textNeedsSplitting($text));
+ $splitText = $templateProcessor->splitTextIntoTexts($text);
+ self::assertFalse($templateProcessor->textNeedsSplitting($splitText));
+ }
+
+ /**
+ * @covers ::textNeedsSplitting
+ */
+ public function testTextNeedsSplittingWithCustomMacro(): void
+ {
+ $templateProcessor = new TestableTemplateProcesor();
+ $templateProcessor->setMacroChars('{{', '}}');
+
+ self::assertFalse($templateProcessor->textNeedsSplitting('{{nothing-to-replace}} '));
+
+ $text = 'Hello {{firstname}} {{lastname}} ';
+ self::assertTrue($templateProcessor->textNeedsSplitting($text));
+ $splitText = $templateProcessor->splitTextIntoTexts($text);
+ self::assertFalse($templateProcessor->textNeedsSplitting($splitText));
+ }
+
+ /**
+ * @covers ::splitTextIntoTexts
+ */
+ public function testSplitTextIntoTexts(): void
+ {
+ $templateProcessor = new TestableTemplateProcesor();
+
+ $splitText = $templateProcessor->splitTextIntoTexts('${nothing-to-replace} ');
+ self::assertEquals('${nothing-to-replace} ', $splitText);
+
+ $splitText = $templateProcessor->splitTextIntoTexts('Hello ${firstname} ${lastname} ');
+ self::assertEquals('Hello ${firstname} ${lastname} ', $splitText);
+ }
+
+ /**
+ * @covers ::splitTextIntoTexts
+ */
+ public function testSplitTextIntoTextsWithCustomMacro(): void
+ {
+ $templateProcessor = new TestableTemplateProcesor();
+ $templateProcessor->setMacroChars('{{', '}}');
+
+ $splitText = $templateProcessor->splitTextIntoTexts('{{nothing-to-replace}} ');
+ self::assertEquals('{{nothing-to-replace}} ', $splitText);
+
+ $splitText = $templateProcessor->splitTextIntoTexts('Hello {{firstname}} {{lastname}} ');
+ self::assertEquals('Hello {{firstname}} {{lastname}} ', $splitText);
+ }
+
+ public function testFindXmlBlockStart(): void
+ {
+ $toFind = '
+
+
+
+
+ This whole paragraph will be replaced with my ${title}
+ ';
+ $mainPart = '
+
+
+
+
+
+
+ ${value1} ${value2}
+
+
+
+
+
+
+ .
+
+
+
+
+
+
+
+
+
+ ' . $toFind . '
+
+ ';
+
+ $templateProcessor = new TestableTemplateProcesor($mainPart);
+ $position = $templateProcessor->findContainingXmlBlockForMacro('${title}', 'w:r');
+
+ self::assertEquals($toFind, $templateProcessor->getSlice($position['start'], $position['end']));
+ }
+
+ public function testFindXmlBlockStartWithCustomMacro(): void
+ {
+ $toFind = '
+
+
+
+
+ This whole paragraph will be replaced with my {{title}}
+ ';
+ $mainPart = '
+
+
+
+
+
+
+ {{value1}} {{value2}}
+
+
+
+
+
+
+ .
+
+
+
+
+
+
+
+
+
+ ' . $toFind . '
+
+ ';
+
+ $templateProcessor = new TestableTemplateProcesor($mainPart);
+ $templateProcessor->setMacroChars('{{', '}}');
+ $position = $templateProcessor->findContainingXmlBlockForMacro('{{title}}', 'w:r');
+
+ self::assertEquals($toFind, $templateProcessor->getSlice($position['start'], $position['end']));
+ }
+
+ public function testShouldReturnFalseIfXmlBlockNotFound(): void
+ {
+ $mainPart = '
+
+
+
+
+
+ this is my text containing a ${macro}
+
+
+ ';
+ $templateProcessor = new TestableTemplateProcesor($mainPart);
+
+ //non-existing macro
+ $result = $templateProcessor->findContainingXmlBlockForMacro('${fake-macro}', 'w:p');
+ self::assertFalse($result);
+
+ //existing macro but not inside node looked for
+ $result = $templateProcessor->findContainingXmlBlockForMacro('${macro}', 'w:fake-node');
+ self::assertFalse($result);
+
+ //existing macro but end tag not found after macro
+ $result = $templateProcessor->findContainingXmlBlockForMacro('${macro}', 'w:rPr');
+ self::assertFalse($result);
+ }
+
+ public function testShouldReturnFalseIfXmlBlockNotFoundWithCustomMacro(): void
+ {
+ $mainPart = '
+
+
+
+
+
+ this is my text containing a ${macro}
+
+
+ ';
+ $templateProcessor = new TestableTemplateProcesor($mainPart);
+ $templateProcessor->setMacroChars('{{', '}}');
+
+ //non-existing macro
+ $result = $templateProcessor->findContainingXmlBlockForMacro('{{fake-macro}}', 'w:p');
+ self::assertFalse($result);
+
+ //existing macro but not inside node looked for
+ $result = $templateProcessor->findContainingXmlBlockForMacro('{{macro}}', 'w:fake-node');
+ self::assertFalse($result);
+
+ //existing macro but end tag not found after macro
+ $result = $templateProcessor->findContainingXmlBlockForMacro('{{macro}}', 'w:rPr');
+ self::assertFalse($result);
+ }
+
+ public function testShouldMakeFieldsUpdateOnOpen(): void
+ {
+ $settingsPart = '
+
+ ';
+ $templateProcessor = new TestableTemplateProcesor(null, $settingsPart);
+
+ $templateProcessor->setUpdateFields(true);
+ self::assertStringContainsString(' ', $templateProcessor->getSettingsPart());
+
+ $templateProcessor->setUpdateFields(false);
+ self::assertStringContainsString(' ', $templateProcessor->getSettingsPart());
+ }
+
+ public function testShouldMakeFieldsUpdateOnOpenWithCustomMacro(): void
+ {
+ $settingsPart = '
+
+ ';
+ $templateProcessor = new TestableTemplateProcesor(null, $settingsPart);
+ $templateProcessor->setMacroChars('{{', '}}');
+
+ $templateProcessor->setUpdateFields(true);
+ self::assertStringContainsString(' ', $templateProcessor->getSettingsPart());
+
+ $templateProcessor->setUpdateFields(false);
+ self::assertStringContainsString(' ', $templateProcessor->getSettingsPart());
+ }
+
+ public function testEnsureUtf8Encoded(): void
+ {
+ $mainPart = '
+
+
+
+
+
+
+
+ ${stringZero}
+
+
+
+
+
+
+ ${intZero}
+
+
+
+
+
+
+ ${stringTest}
+
+
+
+
+
+
+ ${null}
+
+
+
+
+
+
+ ${floatZero}
+
+
+
+
+
+
+ ${intTen}
+
+
+
+
+
+
+ ${boolFalse}
+
+
+
+
+
+
+ ${boolTrue}
+
+
+
+
+ ';
+ $templateProcessor = new TestableTemplateProcesor($mainPart);
+
+ self::assertEquals(
+ ['stringZero', 'intZero', 'stringTest', 'null', 'floatZero', 'intTen', 'boolFalse', 'boolTrue'],
+ $templateProcessor->getVariables()
+ );
+
+ $templateProcessor->setValue('stringZero', '0');
+ self::assertStringContainsString('0 ', $templateProcessor->getMainPart());
+
+ $templateProcessor->setValue('intZero', 0);
+ self::assertStringContainsString('0 ', $templateProcessor->getMainPart());
+
+ $templateProcessor->setValue('stringTest', 'test');
+ self::assertStringContainsString('test ', $templateProcessor->getMainPart());
+
+ $templateProcessor->setValue('null', null);
+ self::assertStringContainsString(' ', $templateProcessor->getMainPart());
+
+ $templateProcessor->setValue('floatZero', 0.00);
+ self::assertStringContainsString('0 ', $templateProcessor->getMainPart());
+
+ $templateProcessor->setValue('intTen', 10);
+ self::assertStringContainsString('10 ', $templateProcessor->getMainPart());
+
+ $templateProcessor->setValue('boolFalse', false);
+ self::assertStringContainsString(' ', $templateProcessor->getMainPart());
+
+ $templateProcessor->setValue('boolTrue', true);
+ self::assertStringContainsString('1 ', $templateProcessor->getMainPart());
+ }
+}
diff --git a/tests/PhpWord/_includes/TestHelperDOCX.php b/tests/PhpWordTests/TestHelperDOCX.php
similarity index 76%
rename from tests/PhpWord/_includes/TestHelperDOCX.php
rename to tests/PhpWordTests/TestHelperDOCX.php
index 02fa7d78a8..2a6fbabae0 100644
--- a/tests/PhpWord/_includes/TestHelperDOCX.php
+++ b/tests/PhpWordTests/TestHelperDOCX.php
@@ -1,4 +1,5 @@
save(self::$file);
- $zip = new \ZipArchive();
+ $zip = new ZipArchive();
$res = $zip->open(self::$file);
if (true === $res) {
$zip->extractTo(Settings::getTempDir() . '/PhpWord_Unit_Test/');
$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;
}
/**
- * Clear document
+ * Clear document.
*/
- public static function clear()
+ public static function clear(): void
{
- if (file_exists(self::$file)) {
+ 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/');
@@ -80,11 +89,11 @@ public static function clear()
}
/**
- * Delete directory
+ * Delete directory.
*
* @param string $dir
*/
- public static function deleteDir($dir)
+ public static function deleteDir($dir): void
{
foreach (scandir($dir) as $file) {
if ('.' === $file || '..' === $file) {
@@ -96,11 +105,11 @@ public static function deleteDir($dir)
}
}
- rmdir($dir);
+ @rmdir($dir);
}
/**
- * Get file
+ * Get file.
*
* @return string
*/
diff --git a/tests/PhpWord/_includes/TestableTemplateProcesor.php b/tests/PhpWordTests/TestableTemplateProcesor.php
similarity index 94%
rename from tests/PhpWord/_includes/TestableTemplateProcesor.php
rename to tests/PhpWordTests/TestableTemplateProcesor.php
index 80cc748f5d..9d6eb9904e 100644
--- a/tests/PhpWord/_includes/TestableTemplateProcesor.php
+++ b/tests/PhpWordTests/TestableTemplateProcesor.php
@@ -1,4 +1,5 @@
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 @@
+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);
+ }
+}
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 @@
+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 = '
';
+ 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 = ' ';
+ 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 @@
+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 = "\n Sample Text \n
\n";
+ self::assertEquals($expected, $this->xmlWriter->getData());
+ }
+
+ public function testWriteWithFontStyle(): void
+ {
+ $this->element->setFontStyle('customStyle');
+
+ $this->writer->write();
+
+ $expected = "\n Sample Text \n
\n";
+ self::assertEquals($expected, $this->xmlWriter->getData());
+ }
+
+ public function testWriteWithParagraphStyle(): void
+ {
+ $this->element->setParagraphStyle('paragraphStyle');
+
+ $this->writer->write();
+
+ $expected = "\n Sample Text \n
\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 = "Sample Text \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 @@
+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..24db959f6e
--- /dev/null
+++ b/tests/PhpWordTests/Writer/EPub3/Part/AbstractPartTest.php
@@ -0,0 +1,38 @@
+part = $this->getMockForAbstractClass(AbstractPart::class);
+ } else {
+ $this->part = new class() extends AbstractPart {
+ public function write(): string
+ {
+ return '';
+ }
+ };
+ }
+ }
+
+ 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 @@
+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('', $result);
+ self::assertStringContainsString('', $result);
+ self::assertStringContainsString('', $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 @@
+manifest = new Manifest();
+ $phpWord = new PhpWord();
+ $writer = new EPub3($phpWord);
+ $this->manifest->setParentWriter($writer);
+ }
+
+ public function testWrite(): void
+ {
+ $result = $this->manifest->write();
+
+ self::assertStringContainsString('', $result);
+ self::assertIsString($result);
+ self::assertStringContainsString('', $result);
+ self::assertStringContainsString('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('', $result);
+ self::assertStringContainsString('getDocInfo();
+ $properties->setCreator('PHPWord');
+ $properties->setTitle('Test Title');
+ $properties->setKeywords('test, keywords');
+
+ $writer = new EPub3($phpWord);
+ $this->meta->setParentWriter($writer);
+
+ $expected = '\nTest Title en urn:uuid:12345 PHPWord 2023-01-01T00:00:00Z ';
+
+ $result = $this->meta->write();
+
+ self::assertStringContainsString('PHPWord ', $result);
+ self::assertStringContainsString('Test 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 @@
+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 @@
+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 @@
+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..e06cef8a3b
--- /dev/null
+++ b/tests/PhpWordTests/Writer/EPub3/Style/AbstractStyleTest.php
@@ -0,0 +1,35 @@
+getMockForAbstractClass(AbstractStyle::class);
+ } else {
+ /** @var AbstractStyle $style */
+ $style = new class() extends AbstractStyle {
+ public function write(): string
+ {
+ return '';
+ }
+ };
+ }
+
+ $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 @@
+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 @@
+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 @@
+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 @@
+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 @@
+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);
+ }
+}
diff --git a/tests/PhpWordTests/Writer/HTML/DirectionTest.php b/tests/PhpWordTests/Writer/HTML/DirectionTest.php
new file mode 100644
index 0000000000..f3b5830d28
--- /dev/null
+++ b/tests/PhpWordTests/Writer/HTML/DirectionTest.php
@@ -0,0 +1,58 @@
+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/Element/PageBreakTest.php b/tests/PhpWordTests/Writer/HTML/Element/PageBreakTest.php
new file mode 100644
index 0000000000..23f5890e9d
--- /dev/null
+++ b/tests/PhpWordTests/Writer/HTML/Element/PageBreakTest.php
@@ -0,0 +1,74 @@
+ ' . 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/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 @@
+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/Element/TableTest.php b/tests/PhpWordTests/Writer/HTML/Element/TableTest.php
new file mode 100644
index 0000000000..cd0bafaab0
--- /dev/null
+++ b/tests/PhpWordTests/Writer/HTML/Element/TableTest.php
@@ -0,0 +1,235 @@
+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]);
+ }
+
+ 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);
+
+ $cell = $row->addCell();
+ $cell->addText('no vAlign');
+ $cell->getStyle()->setVAlign(VerticalJc::BOTTOM);
+ $cell->getStyle()->setVAlign();
+
+ $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);
+
+ $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'));
+ }
+}
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_EOL, $object->write());
+ }
+
+ public function testHTMLEmptyString(): void
+ {
+ $writer = new HTML();
+ $object = new Text($writer, new BaseText(''));
+
+ self::assertEquals('
' . PHP_EOL, $object->write());
+ }
+}
diff --git a/tests/PhpWordTests/Writer/HTML/ElementTest.php b/tests/PhpWordTests/Writer/HTML/ElementTest.php
new file mode 100644
index 0000000000..3b2580381f
--- /dev/null
+++ b/tests/PhpWordTests/Writer/HTML/ElementTest.php
@@ -0,0 +1,246 @@
+write());
+ }
+ }
+
+ /**
+ * Test write element text.
+ */
+ public function testWriteTextElement(): void
+ {
+ $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);
+
+ self::assertEquals(htmlspecialchars('-A-', ENT_COMPAT, 'UTF-8'), $object->write());
+ }
+
+ /**
+ * Test write TrackChange.
+ */
+ public function testWriteTrackChanges(): void
+ {
+ $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()));
+
+ $dom = Helper::getAsHTML($phpWord);
+ $xpath = new DOMXPath($dom);
+
+ self::assertEquals(1, $xpath->query('/html/body/div/p[1]/ins')->length);
+ self::assertEquals(1, $xpath->query('/html/body/div/p[2]/del')->length);
+ }
+
+ /**
+ * Tests writing table with col span.
+ */
+ public function testWriteColSpan(): void
+ {
+ $phpWord = new PhpWord();
+ $section = $phpWord->addSection();
+ $table = $section->addTable();
+ $row1 = $table->addRow();
+ $cell11 = $row1->addCell(1000, ['gridSpan' => 2, 'bgColor' => '6086B8']);
+ $cell11->addText('cell spanning 2 bellow');
+ $row2 = $table->addRow();
+ $cell21 = $row2->addCell(500, ['bgColor' => 'ffffff']);
+ $cell21->addText('first cell');
+ $cell22 = $row2->addCell(500);
+ $cell22->addText('second cell');
+
+ $dom = Helper::getAsHTML($phpWord);
+ $xpath = new DOMXPath($dom);
+
+ 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/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'));
+ }
+
+ /**
+ * Tests writing table with row span.
+ */
+ public function testWriteRowSpan(): void
+ {
+ $phpWord = new PhpWord();
+ $section = $phpWord->addSection();
+ $table = $section->addTable();
+
+ $row1 = $table->addRow();
+ $row1->addCell(1000, ['vMerge' => 'restart'])->addText('row spanning 3 bellow');
+ $row1->addCell(500)->addText('first cell being spanned');
+
+ $row2 = $table->addRow();
+ $row2->addCell(null, ['vMerge' => 'continue']);
+ $row2->addCell(500)->addText('second cell being spanned');
+
+ $row3 = $table->addRow();
+ $row3->addCell(null, ['vMerge' => 'continue']);
+ $row3->addCell(500)->addText('third cell being spanned');
+
+ $dom = Helper::getAsHTML($phpWord);
+ $xpath = new DOMXPath($dom);
+
+ 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);
+ }
+
+ /**
+ * Tests writing table with rowspan and colspan.
+ */
+ public function testWriteRowSpanAndColSpan(): void
+ {
+ $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);
+
+ self::assertEquals(3, $xpath->query('/html/body/div/table/tr[3]/td')->length);
+ }
+
+ public function testWriteTitleTextRun(): void
+ {
+ $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();
+
+ self::assertStringContainsString($expected, $content);
+ }
+
+ /**
+ * Test write element ListItemRun.
+ */
+ public function testListItemRun(): void
+ {
+ $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, ['bold' => true]);
+
+ $htmlWriter = new HTML($phpWord);
+ $content = $htmlWriter->getContent();
+
+ $dom = new DOMDocument();
+ $dom->loadHTML($content);
+
+ self::assertEquals($expected1, $dom->getElementsByTagName('p')->item(0)->textContent);
+ self::assertEquals($expected2, $dom->getElementsByTagName('p')->item(1)->textContent);
+ }
+
+ /**
+ * Tests writing table with layout.
+ */
+ public function testWriteTableLayout(): void
+ {
+ $phpWord = new PhpWord();
+ $section = $phpWord->addSection();
+ $section->addTable();
+
+ $table1 = $section->addTable(['layout' => \PhpOffice\PhpWord\Style\Table::LAYOUT_FIXED]);
+ $row1 = $table1->addRow();
+ $row1->addCell()->addText('fixed layout table');
+
+ $table2 = $section->addTable(['layout' => \PhpOffice\PhpWord\Style\Table::LAYOUT_AUTO]);
+ $row2 = $table2->addRow();
+ $row2->addCell()->addText('auto layout table');
+
+ $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);
+ 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..0a203b7237
--- /dev/null
+++ b/tests/PhpWordTests/Writer/HTML/FontTest.php
@@ -0,0 +1,356 @@
+defaultFontName = Settings::getDefaultFontName();
+ $this->defaultFontSize = Settings::getDefaultFontSize();
+ $this->defaultFontColor = Settings::getDefaultFontColor();
+ }
+
+ /**
+ * Executed after each method of the class.
+ */
+ protected function tearDown(): void
+ {
+ Settings::setDefaultFontName($this->defaultFontName);
+ Settings::setDefaultFontSize($this->defaultFontSize);
+ 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.
+ */
+ 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::assertNotEmpty($matches);
+ self::assertNotFalse($prg);
+ 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);
+ 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]);
+ }
+
+ /**
+ * 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, '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');
+ $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::assertNotEmpty($matches);
+ self::assertNotFalse($prg);
+ 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);
+ 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]);
+ }
+
+ /**
+ * Tests font names - with generics including for default font.
+ */
+ public function testFontNames3(): 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, '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');
+ $section1->addText('Arial', 'style2');
+ $section1->addText('DejaVu Sans Monospace', 'style3');
+ $section1->addText('Arial with invalid fallback', 'style4');
+
+ $dom = Helper::getAsHTML($phpWord, '', 'monospace');
+ $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::assertNotEmpty($matches);
+ self::assertNotFalse($prg);
+ 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);
+ 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]);
+ }
+
+ /**
+ * Tests white space.
+ */
+ public function testWhiteSpace(): void
+ {
+ $phpWord = new PhpWord();
+ $phpWord->setDefaultFontSize(12);
+ $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);
+ $section1->addText($text, 'style1');
+ $section1->addText($text, 'style2');
+ $section1->addText($text, 'style3');
+ $section1->addText($text, 'style4');
+
+ $dom = Helper::getAsHTML($phpWord, 'pre-wrap');
+ $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; color: #000000; 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]);
+ }
+
+ /**
+ * Tests inline font style.
+ */
+ public function testInline(): void
+ {
+ $phpWord = new PhpWord();
+ $style1 = ['name' => 'Courier New', 'size' => 10, 'whiteSpace' => '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..37f640d28a
--- /dev/null
+++ b/tests/PhpWordTests/Writer/HTML/Helper.php
@@ -0,0 +1,128 @@
+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, 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
+ // 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/HTML/ParagraphTest.php b/tests/PhpWordTests/Writer/HTML/ParagraphTest.php
new file mode 100644
index 0000000000..2b2724dba8
--- /dev/null
+++ b/tests/PhpWordTests/Writer/HTML/ParagraphTest.php
@@ -0,0 +1,138 @@
+ 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, '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);
+ $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
new file mode 100644
index 0000000000..b6748a58c5
--- /dev/null
+++ b/tests/PhpWordTests/Writer/HTML/PartTest.php
@@ -0,0 +1,189 @@
+expectException(\PhpOffice\PhpWord\Exception\Exception::class);
+ $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/PhpWord/Writer/HTML/StyleTest.php b/tests/PhpWordTests/Writer/HTML/StyleTest.php
similarity index 78%
rename from tests/PhpWord/Writer/HTML/StyleTest.php
rename to tests/PhpWordTests/Writer/HTML/StyleTest.php
index 5b60226c3f..6dcb12f630 100644
--- a/tests/PhpWord/Writer/HTML/StyleTest.php
+++ b/tests/PhpWordTests/Writer/HTML/StyleTest.php
@@ -1,4 +1,5 @@
assertEquals('', $object->write());
+ self::assertEquals('', $object->write());
}
}
}
diff --git a/tests/PhpWord/Writer/HTMLTest.php b/tests/PhpWordTests/Writer/HTMLTest.php
similarity index 60%
rename from tests/PhpWord/Writer/HTMLTest.php
rename to tests/PhpWordTests/Writer/HTMLTest.php
index 24a8bca371..cedd9f2f32 100644
--- a/tests/PhpWord/Writer/HTMLTest.php
+++ b/tests/PhpWordTests/Writer/HTMLTest.php
@@ -1,4 +1,5 @@
assertInstanceOf('PhpOffice\\PhpWord\\PhpWord', $object->getPhpWord());
+ self::assertInstanceOf(PhpWord::class, $object->getPhpWord());
}
/**
- * Construct with null
- *
- * @expectedException \PhpOffice\PhpWord\Exception\Exception
- * @expectedExceptionMessage No PhpWord assigned.
+ * Construct with null.
*/
- public function testConstructWithNull()
+ public function testConstructWithNull(): void
{
+ $this->expectException(\PhpOffice\PhpWord\Exception\Exception::class);
+ $this->expectExceptionMessage('No PhpWord assigned.');
$object = new HTML();
$object->getPhpWord();
}
+ public function testEditCallback(): void
+ {
+ $object = new HTML(new PhpWord());
+
+ self::assertNull($object->getEditCallback());
+
+ $object->setEditCallback(function (string $html): string {
+ return $html;
+ });
+ self::assertIsCallable($object->getEditCallback());
+
+ $object->setEditCallback(null);
+ self::assertNull($object->getEditCallback());
+ }
+
+ public function testDefaultGenericFont(): void
+ {
+ $object = new HTML(new PhpWord());
+
+ self::assertEquals('', $object->getDefaultGenericFont());
+
+ $object->setDefaultGenericFont('test');
+ self::assertEquals('', $object->getDefaultGenericFont());
+
+ $object->setDefaultGenericFont('cursive');
+ self::assertEquals('cursive', $object->getDefaultGenericFont());
+ }
+
+ public function testDefaultWhiteSpace(): void
+ {
+ $object = new HTML(new PhpWord());
+
+ self::assertEquals('', $object->getDefaultWhiteSpace());
+
+ $object->setDefaultWhiteSpace('test');
+ self::assertEquals('', $object->getDefaultWhiteSpace());
+
+ $object->setDefaultWhiteSpace('pre-line');
+ self::assertEquals('pre-line', $object->getDefaultWhiteSpace());
+ }
+
/**
- * Save
+ * Save.
*/
- public function testSave()
+ public function testSave(): void
{
$localImage = __DIR__ . '/../_files/images/PhpWord.png';
$archiveImage = 'zip://' . __DIR__ . '/../_files/documents/reader.docx#word/media/image1.jpeg';
@@ -67,19 +109,19 @@ public function testSave()
$docProps = $phpWord->getDocInfo();
$docProps->setTitle(htmlspecialchars('HTML Test', ENT_COMPAT, 'UTF-8'));
- $phpWord->addTitleStyle(1, array('bold' => true));
+ $phpWord->addTitleStyle(1, ['bold' => true]);
$phpWord->addFontStyle(
'Font',
- array('name' => 'Verdana', 'size' => 11, 'color' => 'FF0000', 'fgColor' => 'FF0000')
+ ['name' => 'Verdana', 'size' => 11, 'color' => 'FF0000', 'fgColor' => 'FF0000']
);
- $phpWord->addParagraphStyle('Paragraph', array('alignment' => Jc::CENTER, 'spaceAfter' => 20, 'spaceBefore' => 20));
+ $phpWord->addParagraphStyle('Paragraph', ['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(
htmlspecialchars('Test 2', ENT_COMPAT, 'UTF-8'),
- array('name' => 'Tahoma', 'bold' => true, 'italic' => true, 'subscript' => true)
+ ['name' => 'Tahoma', 'bold' => true, 'italic' => true, 'subscript' => true]
);
$section->addLink('https://github.com/PHPOffice/PHPWord');
$section->addTitle(htmlspecialchars('Test', ENT_COMPAT, 'UTF-8'), 1);
@@ -94,17 +136,17 @@ public function testSave()
$section = $phpWord->addSection();
- $textrun = $section->addTextRun(array('alignment' => Jc::CENTER));
+ $textrun = $section->addTextRun(['alignment' => Jc::CENTER]);
$textrun->addText(htmlspecialchars('Test 3', ENT_COMPAT, 'UTF-8'));
$textrun->addTextBreak();
- $textrun = $section->addTextRun(array('alignment' => Jc::START));
+ $textrun = $section->addTextRun(['alignment' => Jc::START]);
$textrun->addText(htmlspecialchars('Text left aligned', ENT_COMPAT, 'UTF-8'));
- $textrun = $section->addTextRun(array('alignment' => Jc::BOTH));
+ $textrun = $section->addTextRun(['alignment' => Jc::BOTH]);
$textrun->addText(htmlspecialchars('Text justified', ENT_COMPAT, 'UTF-8'));
- $textrun = $section->addTextRun(array('alignment' => Jc::END));
+ $textrun = $section->addTextRun(['alignment' => Jc::END]);
$textrun->addText(htmlspecialchars('Text right aligned', ENT_COMPAT, 'UTF-8'));
$textrun = $section->addTextRun('Paragraph');
@@ -119,7 +161,7 @@ public function testSave()
$cell = $table->addRow()->addCell();
$cell->addText(
htmlspecialchars('Test 1', ENT_COMPAT, 'UTF-8'),
- array('superscript' => true, 'underline' => 'dash', 'strikethrough' => true)
+ ['superscript' => true, 'underline' => 'dash', 'strikethrough' => true]
);
$cell->addTextRun();
$cell->addLink('https://github.com/PHPOffice/PHPWord');
@@ -135,12 +177,12 @@ public function testSave()
$writer = new HTML($phpWord);
$writer->save($file);
- $this->assertFileExists($file);
+ self::assertFileExists($file);
unlink($file);
Settings::setOutputEscapingEnabled(true);
$writer->save($file);
- $this->assertFileExists($file);
+ self::assertFileExists($file);
unlink($file);
}
}
diff --git a/tests/PhpWordTests/Writer/ODText/Element/FieldTest.php b/tests/PhpWordTests/Writer/ODText/Element/FieldTest.php
new file mode 100644
index 0000000000..0f936d053e
--- /dev/null
+++ b/tests/PhpWordTests/Writer/ODText/Element/FieldTest.php
@@ -0,0 +1,65 @@
+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/ODText/Element/FormulaTest.php b/tests/PhpWordTests/Writer/ODText/Element/FormulaTest.php
new file mode 100644
index 0000000000..c834a465f0
--- /dev/null
+++ b/tests/PhpWordTests/Writer/ODText/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, '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/Element/ImageTest.php b/tests/PhpWordTests/Writer/ODText/Element/ImageTest.php
new file mode 100644
index 0000000000..ff7788df26
--- /dev/null
+++ b/tests/PhpWordTests/Writer/ODText/Element/ImageTest.php
@@ -0,0 +1,128 @@
+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('', $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('end', $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::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'));
+ }
+
+ /**
+ * Test writing image, with non-default bidi.
+ */
+ public function testImage2(): void
+ {
+ $phpWord = new PhpWord();
+ Settings::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'));
+ 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/Writer/ODText/Element/ListItemRunTest.php b/tests/PhpWordTests/Writer/ODText/Element/ListItemRunTest.php
new file mode 100644
index 0000000000..9f531255fc
--- /dev/null
+++ b/tests/PhpWordTests/Writer/ODText/Element/ListItemRunTest.php
@@ -0,0 +1,83 @@
+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/ElementTest.php b/tests/PhpWordTests/Writer/ODText/ElementTest.php
new file mode 100644
index 0000000000..8ca327717c
--- /dev/null
+++ b/tests/PhpWordTests/Writer/ODText/ElementTest.php
@@ -0,0 +1,367 @@
+write();
+
+ 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(): void
+ {
+ $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(): void
+ {
+ $phpWord = new PhpWord();
+ $section = $phpWord->addSection();
+
+ $table = $section->addTable(['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;
+ /** @var null|string $tableStyleName */
+ $tableStyleName = null;
+ $element = '';
+ while ($tableStyleName === null) {
+ $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::assertNotNull($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-name'));
+ self::assertTrue($doc->elementExists($tableRootElement . '/table:table-column[4]'));
+ }
+
+ /**
+ * 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, 'ODText');
+
+ $p2t = '/office:document-content/office:body/office:text/text:section';
+ $element = "$p2t/text:h[1]";
+ self::assertTrue($doc->elementExists($element));
+ self::assertEquals('HE0', $doc->getElementAttribute($element, 'text:style-name'));
+ self::assertEquals('0', $doc->getElementAttribute($element, 'text:outline-level'));
+ $span = "$element/text:span";
+ self::assertTrue($doc->elementExists($span));
+ self::assertEquals('This is a title', $doc->getElement($span)->textContent);
+ self::assertEquals('Title', $doc->getElementAttribute($span, 'text:style-name'));
+
+ $element = "$p2t/text:h[2]";
+ self::assertTrue($doc->elementExists($element));
+ self::assertEquals('HD1', $doc->getElementAttribute($element, 'text:style-name'));
+ self::assertEquals('1', $doc->getElementAttribute($element, 'text:outline-level'));
+ $span = "$element/text:span";
+ self::assertTrue($doc->elementExists($span));
+ self::assertEquals('Heading 1', $doc->getElement($span)->textContent);
+ self::assertEquals('Heading_1', $doc->getElementAttribute($span, 'text:style-name'));
+
+ $doc->setDefaultFile('styles.xml');
+ $element = '/office:document-styles/office:styles/style:style[1]';
+ self::assertTrue($doc->elementExists($element));
+ self::assertEquals('Title', $doc->getElementAttribute($element, 'style:name'));
+ $element .= '/style:text-properties';
+ self::assertTrue($doc->elementExists($element));
+ self::assertEquals('14pt', $doc->getElementAttribute($element, 'fo:font-size'));
+ self::assertEquals('italic', $doc->getElementAttribute($element, 'fo:font-style'));
+ self::assertEquals('', $doc->getElementAttribute($element, 'fo:font-weight'));
+ self::assertEquals('', $doc->getElementAttribute($element, 'fo:color'));
+
+ $element = '/office:document-styles/office:styles/style:style[2]';
+ self::assertTrue($doc->elementExists($element));
+ self::assertEquals('Heading_1', $doc->getElementAttribute($element, 'style:name'));
+ $element .= '/style:text-properties';
+ self::assertTrue($doc->elementExists($element));
+ self::assertEquals('20pt', $doc->getElementAttribute($element, 'fo:font-size'));
+ self::assertEquals('', $doc->getElementAttribute($element, 'fo:font-style'));
+ self::assertEquals('bold', $doc->getElementAttribute($element, 'fo:font-weight'));
+ self::assertEquals('#333333', $doc->getElementAttribute($element, 'fo:color'));
+ }
+
+ /**
+ * Test title specified as text run rather than text.
+ */
+ public function testTextRunTitle(): void
+ {
+ $phpWord = new PhpWord();
+ $phpWord->addTitleStyle(1, ['name' => 'Times New Roman', 'size' => 18, 'bold' => true]);
+ $section = $phpWord->addSection();
+ $section->addTitle('Text Title', 1);
+ $section->addText('Text following Text Title');
+ $textRun = new 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]";
+ self::assertEquals('HE1', $doc->getElementAttribute($element, 'text:style-name'));
+ self::assertEquals('1', $doc->getElementAttribute($element, 'text:outline-level'));
+ $span = "$element/text:span";
+ self::assertEquals('Text Title', $doc->getElement($span)->textContent);
+ self::assertEquals('Heading_1', $doc->getElementAttribute($span, 'text:style-name'));
+ $element = "$p2t/text:p[2]/text:span";
+ self::assertEquals('Text following Text Title', $doc->getElement($element)->nodeValue);
+
+ $element = "$p2t/text:h[2]";
+ self::assertEquals('HD1', $doc->getElementAttribute($element, 'text:style-name'));
+ self::assertEquals('1', $doc->getElementAttribute($element, 'text:outline-level'));
+ $span = "$element/text:span";
+ self::assertEquals('Text Run', $doc->getElement("$span/text:span[1]")->textContent);
+ self::assertTrue($doc->elementExists("$span/text:span[2]/text:s"));
+ self::assertEquals('Title', $doc->getElement("$span/text:span[2]")->textContent);
+ self::assertEquals('Heading_1', $doc->getElementAttribute($span, 'text:style-name'));
+ $element = "$p2t/text:p[3]/text:span";
+ self::assertEquals('Text following Text Run Title', $doc->getElement($element)->nodeValue);
+ }
+
+ /**
+ * Test correct writing of text with ampersand in it.
+ */
+ public function testTextWithAmpersand(): void
+ {
+ $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]";
+ self::assertTrue($doc->elementExists($element));
+ $span = "$element/text:span";
+ self::assertTrue($doc->elementExists($span));
+ self::assertEquals($txt, $doc->getElement($span)->nodeValue);
+ }
+
+ /**
+ * Test PageBreak.
+ */
+ public function testPageBreak(): void
+ {
+ $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[3]';
+ self::assertTrue($doc->elementExists($element, 'content.xml'));
+ self::assertEquals('PB', $doc->getElementAttribute($element, 'text:style-name', 'content.xml'));
+ }
+
+ /**
+ * Test tracked changes.
+ */
+ public function testTrackedChanges(): void
+ {
+ $phpWord = new PhpWord();
+
+ // New portrait section
+ $section = $phpWord->addSection();
+ $textRun = $section->addTextRun();
+
+ $text = $textRun->addText('Hello World! Time to ');
+
+ $text = $textRun->addText('wake ', ['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'));
+ }
+
+ /**
+ * 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/ODText/Part/AbstractPartTest.php b/tests/PhpWordTests/Writer/ODText/Part/AbstractPartTest.php
new file mode 100644
index 0000000000..049b9e7cb4
--- /dev/null
+++ b/tests/PhpWordTests/Writer/ODText/Part/AbstractPartTest.php
@@ -0,0 +1,74 @@
+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());
+ }
+
+ /**
+ * covers ::getParentWriter.
+ */
+ 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 {
+ /** @var ODText\Part\AbstractPart $object */
+ $object = new class() extends ODText\Part\AbstractPart {
+ public function write(): string
+ {
+ return '';
+ }
+ };
+ }
+ $object->getParentWriter();
+ }
+}
diff --git a/tests/PhpWord/Writer/ODText/Part/ContentTest.php b/tests/PhpWordTests/Writer/ODText/Part/ContentTest.php
similarity index 72%
rename from tests/PhpWord/Writer/ODText/Part/ContentTest.php
rename to tests/PhpWordTests/Writer/ODText/Part/ContentTest.php
index 2e501c6024..e1dc78a32b 100644
--- a/tests/PhpWord/Writer/ODText/Part/ContentTest.php
+++ b/tests/PhpWordTests/Writer/ODText/Part/ContentTest.php
@@ -1,4 +1,5 @@
setCustomProperty('Company', 'PHPWord');
$phpWord->setDefaultFontName('Verdana');
- $phpWord->addFontStyle('Font', array('size' => 11));
- $phpWord->addParagraphStyle('Paragraph', array('alignment' => Jc::CENTER));
- $phpWord->addTableStyle('tblStyle', array('width' => 100));
+ $phpWord->addFontStyle('Font', ['size' => 11]);
+ $phpWord->addParagraphStyle('Paragraph', ['alignment' => Jc::CENTER]);
+ $phpWord->addTableStyle('tblStyle', ['width' => 100]);
- $section = $phpWord->addSection(array('colsNum' => 2));
+ $section = $phpWord->addSection(['colsNum' => 2]);
$section->addText($expected);
$section->addText('Test font style', 'Font');
$section->addText('Test paragraph style', null, 'Paragraph');
@@ -65,14 +65,14 @@ public function testWriteContent()
$section->addTextBreak();
$section->addPageBreak();
$section->addListItem('Test list item');
- $section->addImage($imageSrc, array('width' => 50));
+ $section->addImage($imageSrc, ['width' => 50]);
$section->addObject($objectSrc);
$section->addTOC();
$textrun = $section->addTextRun();
$textrun->addText('Test text run');
- $table = $section->addTable(array('width' => 50));
+ $table = $section->addTable(['width' => 50]);
$cell = $table->addRow()->addCell();
$cell = $table->addRow()->addCell();
$cell->addText('Test');
@@ -92,21 +92,21 @@ public function testWriteContent()
$doc = TestHelperDOCX::getDocument($phpWord, 'ODText');
- $element = '/office:document-content/office:body/office:text/text:section/text:p';
- $this->assertEquals($expected, $doc->getElement($element, 'content.xml')->nodeValue);
+ $element = '/office:document-content/office:body/office:text/text:section/text:p[2]';
+ self::assertEquals($expected, $doc->getElement($element, 'content.xml')->nodeValue);
}
/**
- * Test no paragraph style
+ * Test no paragraph style.
*/
- public function testWriteNoStyle()
+ public function testWriteNoStyle(): void
{
$phpWord = new PhpWord();
- $phpWord->addFontStyle('Font', array('size' => 11));
+ $phpWord->addFontStyle('Font', ['size' => 11]);
$doc = TestHelperDOCX::getDocument($phpWord, 'ODText');
$element = '/office:document-content/office:automatic-styles/style:style';
- $this->assertTrue($doc->elementExists($element, 'content.xml'));
+ self::assertTrue($doc->elementExists($element, 'content.xml'));
}
}
diff --git a/tests/PhpWordTests/Writer/ODText/Part/ManifestTest.php b/tests/PhpWordTests/Writer/ODText/Part/ManifestTest.php
new file mode 100644
index 0000000000..bfe5253cda
--- /dev/null
+++ b/tests/PhpWordTests/Writer/ODText/Part/ManifestTest.php
@@ -0,0 +1,101 @@
+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/ODText/Style/FontTest.php b/tests/PhpWordTests/Writer/ODText/Style/FontTest.php
new file mode 100644
index 0000000000..b377ff4fcd
--- /dev/null
+++ b/tests/PhpWordTests/Writer/ODText/Style/FontTest.php
@@ -0,0 +1,287 @@
+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.
+ */
+ public function testColors(): void
+ {
+ $phpWord = new \PhpOffice\PhpWord\PhpWord();
+ $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' => Font::FGCOLOR_DARKGREEN]);
+ $section->addText('This color is default (unknow)', ['color' => 'unknow']);
+
+ $doc = TestHelperDOCX::getDocument($phpWord, 'ODText');
+ $s2a = '/office:document-content/office:automatic-styles';
+ self::assertTrue($doc->elementExists($s2a));
+ $s2t = '/office:document-content/office:body/office:text/text:section';
+ self::assertTrue($doc->elementExists($s2t));
+
+ $element = "$s2a/style:style[5]";
+ self::assertTrue($doc->elementExists($element));
+ $style = $doc->getElementAttribute($element, 'style:name');
+ $element .= '/style:text-properties';
+ self::assertTrue($doc->elementExists($element));
+ self::assertEquals('#008787', $doc->getElementAttribute($element, 'fo:color'));
+ $span = "$s2t/text:p[3]/text:span";
+ self::assertTrue($doc->elementExists($span));
+ self::assertEquals($style, $doc->getElementAttribute($span, 'text:style-name'));
+ self::assertEquals('This should be cyanish (008787)', $doc->getElement($span)->nodeValue);
+
+ $element = "$s2a/style:style[7]";
+ self::assertTrue($doc->elementExists($element));
+ $style = $doc->getElementAttribute($element, 'style:name');
+ $element .= '/style:text-properties';
+ self::assertTrue($doc->elementExists($element));
+ self::assertEquals('#006400', $doc->getElementAttribute($element, 'fo:color'));
+ $span = "$s2t/text:p[4]/text:span";
+ self::assertTrue($doc->elementExists($span));
+ self::assertEquals($style, $doc->getElementAttribute($span, 'text:style-name'));
+ self::assertEquals('This should be dark green (FGCOLOR_DARKGREEN)', $doc->getElement($span)->nodeValue);
+ }
+
+ public static function providerAllNamedColors()
+ {
+ return [
+ [Font::FGCOLOR_YELLOW, 'FFFF00'],
+ [Font::FGCOLOR_LIGHTGREEN, '90EE90'],
+ [Font::FGCOLOR_CYAN, '00FFFF'],
+ [Font::FGCOLOR_MAGENTA, 'FF00FF'],
+ [Font::FGCOLOR_BLUE, '0000FF'],
+ [Font::FGCOLOR_RED, 'FF0000'],
+ [Font::FGCOLOR_DARKBLUE, '00008B'],
+ [Font::FGCOLOR_DARKCYAN, '008B8B'],
+ [Font::FGCOLOR_DARKGREEN, '006400'],
+ [Font::FGCOLOR_DARKMAGENTA, '8B008B'],
+ [Font::FGCOLOR_DARKRED, '8B0000'],
+ [Font::FGCOLOR_DARKYELLOW, '8B8B00'],
+ [Font::FGCOLOR_DARKGRAY, 'A9A9A9'],
+ [Font::FGCOLOR_LIGHTGRAY, 'D3D3D3'],
+ [Font::FGCOLOR_BLACK, '000000'],
+ ['unknow', 'unknow'],
+ ['unknown', 'unknown'],
+ ];
+ }
+
+ /**
+ * @dataProvider providerAllNamedColors
+ *
+ * @param string $namedColor
+ * @param string $rgbColor
+ */
+ public function testAllNamedColors($namedColor, $rgbColor): void
+ {
+ $phpWord = new \PhpOffice\PhpWord\PhpWord();
+ $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($namedColor, ['color' => $namedColor]);
+
+ $doc = TestHelperDOCX::getDocument($phpWord, 'ODText');
+ $s2a = '/office:document-content/office:automatic-styles';
+ self::assertTrue($doc->elementExists($s2a));
+ $s2t = '/office:document-content/office:body/office:text/text:section';
+ self::assertTrue($doc->elementExists($s2t));
+
+ $element = "$s2a/style:style[7]";
+ self::assertTrue($doc->elementExists($element));
+ $style = $doc->getElementAttribute($element, 'style:name');
+ $element .= '/style:text-properties';
+ self::assertTrue($doc->elementExists($element));
+ self::assertEquals("#$rgbColor", $doc->getElementAttribute($element, 'fo:color'));
+ $span = "$s2t/text:p[4]/text:span";
+ self::assertTrue($doc->elementExists($span));
+ self::assertEquals($style, $doc->getElementAttribute($span, 'text:style-name'));
+ self::assertEquals($namedColor, $doc->getElement($span)->nodeValue);
+ }
+
+ /**
+ * Test noproof.
+ */
+ public function testNoProof(): void
+ {
+ $phpWord = new \PhpOffice\PhpWord\PhpWord();
+ $section = $phpWord->addSection();
+ $section->addText('Noproof not specified', ['color' => 'black']);
+ $section->addText('Noproof is true', ['color' => 'black', 'noproof' => true]);
+ $section->addText('Noproof is false', ['color' => 'black', 'noproof' => false]);
+
+ $doc = TestHelperDOCX::getDocument($phpWord, 'ODText');
+ $s2a = '/office:document-content/office:automatic-styles';
+ self::assertTrue($doc->elementExists($s2a));
+ $s2t = '/office:document-content/office:body/office:text/text:section';
+ self::assertTrue($doc->elementExists($s2t));
+
+ $element = "$s2a/style:style[3]";
+ self::assertTrue($doc->elementExists($element));
+ $style = $doc->getElementAttribute($element, 'style:name');
+ $element .= '/style:text-properties';
+ self::assertTrue($doc->elementExists($element));
+ self::assertEquals('', $doc->getElementAttribute($element, 'fo:language'));
+ $span = "$s2t/text:p[2]/text:span";
+ self::assertTrue($doc->elementExists($span));
+ self::assertEquals($style, $doc->getElementAttribute($span, 'text:style-name'));
+ self::assertEquals('Noproof not specified', $doc->getElement($span)->nodeValue);
+
+ $element = "$s2a/style:style[5]";
+ self::assertTrue($doc->elementExists($element));
+ $style = $doc->getElementAttribute($element, 'style:name');
+ $element .= '/style:text-properties';
+ self::assertTrue($doc->elementExists($element));
+ self::assertEquals('zxx', $doc->getElementAttribute($element, 'fo:language'));
+ self::assertEquals('zxx', $doc->getElementAttribute($element, 'style:language-asian'));
+ self::assertEquals('zxx', $doc->getElementAttribute($element, 'style:language-complex'));
+ self::assertEquals('none', $doc->getElementAttribute($element, 'fo:country'));
+ self::assertEquals('none', $doc->getElementAttribute($element, 'style:country-asian'));
+ self::assertEquals('none', $doc->getElementAttribute($element, 'style:country-complex'));
+ $span = "$s2t/text:p[3]/text:span";
+ self::assertTrue($doc->elementExists($span));
+ self::assertEquals($style, $doc->getElementAttribute($span, 'text:style-name'));
+ self::assertEquals('Noproof is true', $doc->getElement($span)->nodeValue);
+
+ $element = "$s2a/style:style[7]";
+ self::assertTrue($doc->elementExists($element));
+ $style = $doc->getElementAttribute($element, 'style:name');
+ $element .= '/style:text-properties';
+ self::assertTrue($doc->elementExists($element));
+ self::assertEquals('', $doc->getElementAttribute($element, 'fo:language'));
+ $span = "$s2t/text:p[4]/text:span";
+ self::assertTrue($doc->elementExists($span));
+ self::assertEquals($style, $doc->getElementAttribute($span, 'text:style-name'));
+ self::assertEquals('Noproof is false', $doc->getElement($span)->nodeValue);
+ }
+
+ /**
+ * Test using object with a name as font style for addText.
+ */
+ public function testNamedStyleAsObject(): void
+ {
+ $phpWord = new \PhpOffice\PhpWord\PhpWord();
+ $named = $phpWord->addFontStyle('namedobject', ['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';
+ self::assertTrue($doc->elementExists($s2t));
+ $element = "$s2t/text:p[2]/text:span";
+ self::assertTrue($doc->elementExists($element));
+ self::assertEquals('namedobject', $doc->getElementAttribute($element, 'text:style-name'));
+ }
+
+ /**
+ * Test supplying field font style as array or object or string.
+ */
+ public function testFieldStyles(): void
+ {
+ $phpWord = new \PhpOffice\PhpWord\PhpWord();
+ $namedstyle = $phpWord->addFontStyle('namedstyle', ['color' => '800000']);
+ $section = $phpWord->addSection();
+ $textrun = $section->addTextRun();
+ $fld = $textrun->addField('DATE');
+ $fld->setFontStyle('namedstyle');
+ $textrun = $section->addTextRun();
+ $fld = $textrun->addField('DATE');
+ $fld->setFontStyle(['color' => '008000']);
+ $textrun = $section->addTextRun();
+ $fld = $textrun->addField('DATE');
+ $font = new 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';
+ $s2t = '/office:document-content/office:body/office:text/text:section';
+
+ $element = "$s2a/style:style[5]";
+ self::assertEquals('T1', $doc->getElementAttribute($element, 'style:name'));
+ self::assertEquals('#008000', $doc->getElementAttribute("$element/style:text-properties", 'fo:color'));
+ $element = "$s2a/style:style[7]";
+ self::assertEquals('T2', $doc->getElementAttribute($element, 'style:name'));
+ self::assertEquals('#000080', $doc->getElementAttribute("$element/style:text-properties", 'fo:color'));
+
+ $element = "$s2t/text:p[2]/text:span";
+ self::assertEquals('namedstyle', $doc->getElementAttribute($element, 'text:style-name'));
+ self::assertTrue($doc->elementExists("$element/text:date"));
+ $element = "$s2t/text:p[3]/text:span";
+ self::assertEquals('T1', $doc->getElementAttribute($element, 'text:style-name'));
+ self::assertTrue($doc->elementExists("$element/text:date"));
+ $element = "$s2t/text:p[4]/text:span";
+ self::assertEquals('T2', $doc->getElementAttribute($element, 'text:style-name'));
+ self::assertTrue($doc->elementExists("$element/text:date"));
+ $element = "$s2t/text:p[5]/text:span";
+ self::assertEquals('namedstyle', $doc->getElementAttribute($element, 'text:style-name'));
+ }
+}
diff --git a/tests/PhpWordTests/Writer/ODText/Style/NumberingTest.php b/tests/PhpWordTests/Writer/ODText/Style/NumberingTest.php
new file mode 100644
index 0000000000..b06242706d
--- /dev/null
+++ b/tests/PhpWordTests/Writer/ODText/Style/NumberingTest.php
@@ -0,0 +1,70 @@
+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'));
+ }
+}
diff --git a/tests/PhpWordTests/Writer/ODText/Style/Paragraph2Test.php b/tests/PhpWordTests/Writer/ODText/Style/Paragraph2Test.php
new file mode 100644
index 0000000000..bc02ca8ea0
--- /dev/null
+++ b/tests/PhpWordTests/Writer/ODText/Style/Paragraph2Test.php
@@ -0,0 +1,155 @@
+ '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();
+ Settings::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();
+ Settings::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 = Settings::isDefaultRtl();
+ self::assertFalse($dflt1);
+ $phpWord = new PhpWord();
+ $dflt2 = Settings::isDefaultRtl();
+ self::assertNull($dflt2);
+ }
+}
diff --git a/tests/PhpWordTests/Writer/ODText/Style/ParagraphTest.php b/tests/PhpWordTests/Writer/ODText/Style/ParagraphTest.php
new file mode 100644
index 0000000000..ecadd387d5
--- /dev/null
+++ b/tests/PhpWordTests/Writer/ODText/Style/ParagraphTest.php
@@ -0,0 +1,466 @@
+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]";
+ self::assertEquals('PB', $doc->getElementAttribute($element, 'style:name'));
+ $element .= '/style:paragraph-properties';
+ self::assertEquals('page', $doc->getElementAttribute($element, 'fo:break-after'));
+ self::assertEquals('0cm', $doc->getElementAttribute($element, 'fo:margin-top'));
+ self::assertEquals('0cm', $doc->getElementAttribute($element, 'fo:margin-bottom'));
+
+ $s2a = '/office:document-content/office:body/office:text/text:section';
+ $element = "$s2a/text:p[3]";
+ self::assertEquals('PB', $doc->getElementAttribute($element, 'text:style-name'));
+ }
+
+ /**
+ * Test normal/indent.
+ */
+ public function testNormalIndent(): void
+ {
+ $phpWord = new PhpWord();
+ $cvt = Converter::INCH_TO_TWIP;
+ $indent1 = ['indentation' => ['left' => 0.50 * $cvt]];
+ $indent2 = ['indentation' => ['left' => 1.00 * $cvt, 'right' => 1.05 * $cvt]];
+ $indent3 = ['indentation' => ['left' => -0.50 * $cvt]];
+ $indent4 = ['indentation' => ['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';
+ 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('', $doc->getElementAttribute($element, 'fo:margin-left'));
+ self::assertEquals('', $doc->getElementAttribute($element, 'fo:margin-right'));
+
+ $element = "$s2a/style:style[6]/style:paragraph-properties";
+ self::assertTrue($doc->elementExists($element));
+ self::assertEquals('1in', $doc->getElementAttribute($element, 'fo:margin-left'));
+ self::assertEquals('1.05in', $doc->getElementAttribute($element, 'fo:margin-right'));
+
+ $element = "$s2a/style:style[8]/style:paragraph-properties";
+ self::assertTrue($doc->elementExists($element));
+ self::assertEquals('-0.5in', $doc->getElementAttribute($element, 'fo:margin-left'));
+ self::assertEquals('0in', $doc->getElementAttribute($element, 'fo:margin-right'));
+
+ $element = "$s2a/style:style[10]/style:paragraph-properties";
+ self::assertTrue($doc->elementExists($element));
+ self::assertEquals('0in', $doc->getElementAttribute($element, 'fo:margin-left'));
+ self::assertEquals('0in', $doc->getElementAttribute($element, 'fo:margin-right'));
+
+ $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('0.5in', $doc->getElementAttribute($element, 'fo:margin-left'));
+ self::assertEquals('0in', $doc->getElementAttribute($element, 'fo:margin-right'));
+ }
+
+ /**
+ * Test textAlign.
+ */
+ public function testTextAlign(): void
+ {
+ $phpWord = new PhpWord();
+ $align1 = ['alignment' => 'end'];
+ $align2 = ['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';
+ 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('', $doc->getElementAttribute($element, 'fo:text-align'));
+
+ $element = "$s2a/style:style[6]/style:paragraph-properties";
+ self::assertTrue($doc->elementExists($element));
+ self::assertEquals('start', $doc->getElementAttribute($element, 'fo:text-align'));
+
+ $element = "$s2a/style:style[8]/style:paragraph-properties";
+ self::assertTrue($doc->elementExists($element));
+ self::assertEquals('end', $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('end', $doc->getElementAttribute($element, 'fo:text-align'));
+ }
+
+ /**
+ * Test lineHeight.
+ */
+ public function testLineHeight(): void
+ {
+ $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, ['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, ['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, ['lineHeight' => 0.90]);
+
+ $doc = TestHelperDOCX::getDocument($phpWord, 'ODText');
+ $s2a = '/office:document-content/office:automatic-styles';
+ self::assertTrue($doc->elementExists($s2a));
+
+ $element = "$s2a/style:style[4]/style:paragraph-properties";
+ self::assertTrue($doc->elementExists($element));
+ self::assertEquals('108%', $doc->getElementAttribute($element, 'fo:line-height'));
+
+ $element = "$s2a/style:style[6]/style:paragraph-properties";
+ self::assertTrue($doc->elementExists($element));
+ self::assertEquals('120%', $doc->getElementAttribute($element, 'fo:line-height'));
+
+ $element = "$s2a/style:style[8]/style:paragraph-properties";
+ self::assertTrue($doc->elementExists($element));
+ self::assertEquals('90%', $doc->getElementAttribute($element, 'fo:line-height'));
+ }
+
+ /**
+ * Test SpaceBeforeAfter.
+ */
+ public function testSpaceBeforeAfter(): void
+ {
+ $phpWord = new PhpWord();
+ $phpWord->setDefaultParagraphStyle(['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, ['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, ['spaceBefore' => 100]);
+ $section->addText('No spacing before this paragraph');
+
+ $doc = TestHelperDOCX::getDocument($phpWord, 'ODText');
+ $s2a = '/office:document-content/office:automatic-styles';
+ self::assertTrue($doc->elementExists($s2a));
+
+ $element = "$s2a/style:style[8]/style:paragraph-properties";
+ self::assertTrue($doc->elementExists($element));
+ self::assertEquals('', $doc->getElementAttribute($element, 'fo:margin-top'));
+ self::assertEquals('5pt', $doc->getElementAttribute($element, 'fo:margin-bottom'));
+
+ $element = "$s2a/style:style[12]/style:paragraph-properties";
+ self::assertTrue($doc->elementExists($element));
+ self::assertEquals('5pt', $doc->getElementAttribute($element, 'fo:margin-top'));
+ self::assertEquals('', $doc->getElementAttribute($element, 'fo:margin-bottom'));
+
+ $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('0pt', $doc->getElementAttribute($element, 'fo:margin-top'));
+ self::assertEquals('0pt', $doc->getElementAttribute($element, 'fo:margin-bottom'));
+ }
+
+ /**
+ * Test Page Break Before.
+ */
+ public function testPageBreakBefore(): void
+ {
+ $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, ['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, ['pageBreakBefore' => true]);
+
+ $doc = TestHelperDOCX::getDocument($phpWord, 'ODText');
+ $s2a = '/office:document-content/office:automatic-styles';
+ self::assertTrue($doc->elementExists($s2a));
+
+ $element = "$s2a/style:style[4]/style:paragraph-properties";
+ self::assertTrue($doc->elementExists($element));
+ self::assertEquals('', $doc->getElementAttribute($element, 'fo:break-before'));
+ $element = "$s2a/style:style[6]/style:paragraph-properties";
+ self::assertTrue($doc->elementExists($element));
+ self::assertEquals('page', $doc->getElementAttribute($element, 'fo:break-before'));
+ $element = "$s2a/style:style[8]/style:paragraph-properties";
+ self::assertTrue($doc->elementExists($element));
+ self::assertEquals('', $doc->getElementAttribute($element, 'fo:break-before'));
+ $element = "$s2a/style:style[10]/style:paragraph-properties";
+ self::assertTrue($doc->elementExists($element));
+ self::assertEquals('page', $doc->getElementAttribute($element, 'fo:break-before'));
+ }
+
+ /**
+ * Test Heading Page Break Before.
+ */
+ public function testHeadingPageBreakBefore(): void
+ {
+ $phpWord = new PhpWord();
+ $phpWord->addTitleStyle(1, null, ['pageBreakBefore' => true]);
+ $phpWord->addTitleStyle(2, null, []);
+ $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';
+ self::assertTrue($doc->elementExists($s2a));
+
+ $element = "$s2a/style:style[4]";
+ self::assertTrue($doc->elementExists($element));
+ self::assertEquals('HD1', $doc->getElementAttribute($element, 'style:name'));
+ self::assertEquals('Heading_1', $doc->getElementAttribute($element, 'style:parent-style-name'));
+ $element .= '/style:paragraph-properties';
+ self::assertTrue($doc->elementExists($element));
+ self::assertEquals('page', $doc->getElementAttribute($element, 'fo:break-before'));
+
+ $element = "$s2a/style:style[5]";
+ self::assertTrue($doc->elementExists($element));
+ self::assertEquals('HE1', $doc->getElementAttribute($element, 'style:name'));
+ self::assertEquals('Heading_1', $doc->getElementAttribute($element, 'style:parent-style-name'));
+ $element .= '/style:paragraph-properties';
+ self::assertTrue($doc->elementExists($element));
+ self::assertEquals('auto', $doc->getElementAttribute($element, 'fo:break-before'));
+
+ $element = "$s2a/style:style[6]";
+ self::assertTrue($doc->elementExists($element));
+ self::assertEquals('HD2', $doc->getElementAttribute($element, 'style:name'));
+ self::assertEquals('Heading_2', $doc->getElementAttribute($element, 'style:parent-style-name'));
+ $element .= '/style:paragraph-properties';
+ self::assertTrue($doc->elementExists($element));
+ self::assertEquals('', $doc->getElementAttribute($element, 'fo:break-before'));
+
+ $element = "$s2a/style:style[7]";
+ self::assertTrue($doc->elementExists($element));
+ self::assertEquals('HE2', $doc->getElementAttribute($element, 'style:name'));
+ self::assertEquals('Heading_2', $doc->getElementAttribute($element, 'style:parent-style-name'));
+ $element .= '/style:paragraph-properties';
+ self::assertTrue($doc->elementExists($element));
+ self::assertEquals('auto', $doc->getElementAttribute($element, 'fo:break-before'));
+
+ $s2a = '/office:document-content/office:body/office:text/text:section[1]';
+ self::assertTrue($doc->elementExists($s2a));
+ $element = "$s2a/text:h[1]";
+ self::assertEquals('HE1', $doc->getElementAttribute($element, 'text:style-name'));
+ self::assertEquals('1', $doc->getElementAttribute($element, 'text:outline-level'));
+ $element .= '/text:span';
+ self::assertEquals('Heading_1', $doc->getElementAttribute($element, 'text:style-name'));
+ $element = "$s2a/text:h[2]";
+ self::assertEquals('HD2', $doc->getElementAttribute($element, 'text:style-name'));
+ self::assertEquals('2', $doc->getElementAttribute($element, 'text:outline-level'));
+ $element .= '/text:span';
+ self::assertEquals('Heading_2', $doc->getElementAttribute($element, 'text:style-name'));
+ $element = "$s2a/text:h[3]";
+ self::assertEquals('HD1', $doc->getElementAttribute($element, 'text:style-name'));
+ self::assertEquals('1', $doc->getElementAttribute($element, 'text:outline-level'));
+ $element .= '/text:span';
+ self::assertEquals('Heading_1', $doc->getElementAttribute($element, 'text:style-name'));
+ $element = "$s2a/text:h[4]";
+ self::assertEquals('HD2', $doc->getElementAttribute($element, 'text:style-name'));
+ self::assertEquals('2', $doc->getElementAttribute($element, 'text:outline-level'));
+ $element .= '/text:span';
+ self::assertEquals('Heading_2', $doc->getElementAttribute($element, 'text:style-name'));
+
+ $s2a = '/office:document-content/office:body/office:text/text:section[2]';
+ self::assertTrue($doc->elementExists($s2a));
+ $element = "$s2a/text:h[1]";
+ self::assertEquals('HE1', $doc->getElementAttribute($element, 'text:style-name'));
+ self::assertEquals('1', $doc->getElementAttribute($element, 'text:outline-level'));
+ $element .= '/text:span';
+ self::assertEquals('Heading_1', $doc->getElementAttribute($element, 'text:style-name'));
+ $element = "$s2a/text:h[2]";
+ self::assertEquals('HD2', $doc->getElementAttribute($element, 'text:style-name'));
+ self::assertEquals('2', $doc->getElementAttribute($element, 'text:outline-level'));
+ $element .= '/text:span';
+ self::assertEquals('Heading_2', $doc->getElementAttribute($element, 'text:style-name'));
+
+ $doc->setDefaultFile('styles.xml');
+ $s2a = '/office:document-styles/office:styles';
+ self::assertTrue($doc->elementExists($s2a));
+ $element = "$s2a/style:style[1]";
+ self::assertEquals('Heading_1', $doc->getElementAttribute($element, 'style:name'));
+ self::assertEquals('paragraph', $doc->getElementAttribute($element, 'style:family'));
+ $element .= '/style:paragraph-properties';
+ self::assertEquals('page', $doc->getElementAttribute($element, 'fo:break-before'));
+ $element = "$s2a/style:style[3]";
+ self::assertEquals('Heading_2', $doc->getElementAttribute($element, 'style:name'));
+ self::assertEquals('paragraph', $doc->getElementAttribute($element, 'style:family'));
+ $element .= '/style:paragraph-properties';
+ self::assertEquals('', $doc->getElementAttribute($element, 'fo:break-before'));
+ }
+
+ /**
+ * Test text run paragraph style using named style.
+ */
+ public function testTextRun(): void
+ {
+ $phpWord = new PhpWord();
+ $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('start', $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('end', $doc->getElementAttribute($element, 'fo:text-align'));
+ }
+
+ /**
+ * Test text run paragraph style using unnamed style.
+ */
+ public function testTextRunUnnamed(): void
+ {
+ $phpWord = new PhpWord();
+ $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('start', $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('end', $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'));
+ }
+
+ /**
+ * Test Empty font and paragraph styles.
+ */
+ public function testEmptyFontAndParagraphStyles(): void
+ {
+ $phpWord = new PhpWord();
+ $section = $phpWord->addSection();
+ $phpWord->addFontStyle('namedfont', ['name' => 'Courier New', 'size' => 8]);
+ $phpWord->addParagraphStyle('namedpar', ['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]";
+ self::assertEquals('Normal', $doc->getElementAttribute($element, 'text:style-name'));
+ self::assertEquals(5, $doc->getElementAttribute("$element/text:s", 'text:c'));
+ self::assertFalse($doc->elementExists("$element/text:span"));
+ $element = "$s2a/text:p[3]";
+ self::assertEquals('Normal', $doc->getElementAttribute($element, 'text:style-name'));
+ self::assertEquals('namedfont', $doc->getElementAttribute("$element/text:span", 'text:style-name'));
+ $element = "$s2a/text:p[4]";
+ self::assertEquals('P1_namedpar', $doc->getElementAttribute($element, 'text:style-name'));
+ self::assertFalse($doc->elementExists("$element/text:span"));
+ $element = "$s2a/text:p[5]";
+ self::assertEquals('P2_namedpar', $doc->getElementAttribute($element, 'text:style-name'));
+ self::assertEquals('namedfont', $doc->getElementAttribute("$element/text:span", 'text:style-name'));
+ }
+}
diff --git a/tests/PhpWordTests/Writer/ODText/Style/SectionTest.php b/tests/PhpWordTests/Writer/ODText/Style/SectionTest.php
new file mode 100644
index 0000000000..83f5962944
--- /dev/null
+++ b/tests/PhpWordTests/Writer/ODText/Style/SectionTest.php
@@ -0,0 +1,250 @@
+addFontStyle('hdrstyle1', ['name' => 'Courier New', 'size' => 8]);
+ $section = $phpWord->addSection(['paperSize' => 'Letter', 'marginTop' => $margins, 'marginBottom' => $margins]);
+ $header = $section->addHeader();
+ $phpWord->addParagraphStyle('centerheader', ['align' => 'center']);
+ $header->addText('Centered Header', 'hdrstyle1', 'centerheader');
+ $footer = $section->addFooter();
+ $sizew = $section->getStyle()->getPageSizeW();
+ $sizel = $section->getStyle()->getMarginLeft();
+ $sizer = $section->getStyle()->getMarginRight();
+ $footerwidth = $sizew - $sizel - $sizer;
+ $phpWord->addParagraphStyle(
+ 'footerTab',
+ [
+ 'tabs' => [
+ 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";
+ self::assertTrue($doc->elementExists($element));
+ self::assertEquals('8.5in', $doc->getElementAttribute($element, 'fo:page-width'));
+ self::assertEquals('11in', $doc->getElementAttribute($element, 'fo:page-height'));
+ self::assertEquals('0.5in', $doc->getElementAttribute($element, 'fo:margin-top'));
+ self::assertEquals('0.5in', $doc->getElementAttribute($element, 'fo:margin-bottom'));
+
+ $s2s = '/office:document-styles/office:styles';
+ $element = "$s2s/style:style[1]";
+ self::assertTrue($doc->elementExists($element));
+ self::assertEquals('hdrstyle1', $doc->getElementAttribute($element, 'style:name'));
+ $tprop = "$element/style:text-properties";
+ self::assertTrue($doc->elementExists($tprop));
+ self::assertEquals('Courier New', $doc->getElementAttribute($tprop, 'style:font-name'));
+
+ $element = "$s2s/style:style[2]";
+ self::assertTrue($doc->elementExists($element));
+ self::assertEquals('centerheader', $doc->getElementAttribute($element, 'style:name'));
+ $tprop = "$element/style:paragraph-properties";
+ self::assertTrue($doc->elementExists($tprop));
+ self::assertEquals('center', $doc->getElementAttribute($tprop, 'fo:text-align'));
+
+ $element = "$s2s/style:style[3]";
+ self::assertTrue($doc->elementExists($element));
+ self::assertEquals('footerTab', $doc->getElementAttribute($element, 'style:name'));
+ $tprop = "$element/style:paragraph-properties/style:tab-stops";
+ self::assertTrue($doc->elementExists($tprop));
+ $tstop = "$tprop/style:tab-stop[1]";
+ self::assertTrue($doc->elementExists($tstop));
+ self::assertEquals('center', $doc->getElementAttribute($tstop, 'style:type'));
+ self::assertEquals('3.25in', $doc->getElementAttribute($tstop, 'style:position'));
+ $tstop = "$tprop/style:tab-stop[2]";
+ self::assertTrue($doc->elementExists($tstop));
+ self::assertEquals('right', $doc->getElementAttribute($tstop, 'style:type'));
+ self::assertEquals('6.5in', $doc->getElementAttribute($tstop, 'style:position'));
+
+ $s2s = '/office:document-styles/office:master-styles/style:master-page/style:footer/text:p';
+ self::assertTrue($doc->elementExists($s2s));
+ $element = "$s2s/text:span[1]";
+ self::assertTrue($doc->elementExists($element));
+ self::assertEquals('hdrstyle1', $doc->getElementAttribute($element, 'text:style-name'));
+ self::assertEquals('Left footer', $doc->getElement($element)->nodeValue);
+ $element = "$s2s/text:span[2]/text:tab";
+ self::assertTrue($doc->elementExists($element));
+ $element = "$s2s/text:span[3]/text:date";
+ self::assertTrue($doc->elementExists($element));
+ $element = "$s2s/text:span[4]/text:tab";
+ self::assertTrue($doc->elementExists($element));
+ $element = "$s2s/text:span[5]";
+ self::assertTrue($doc->elementExists($element));
+ self::assertEquals('Page', $doc->getElement($element)->nodeValue);
+ self::assertTrue($doc->elementExists("$element/text:s"));
+ $element = "$s2s/text:span[6]/text:page-number";
+ self::assertTrue($doc->elementExists($element));
+ $element = "$s2s/text:span[7]";
+ self::assertTrue($doc->elementExists($element));
+ self::assertEquals('of', $doc->getElement($element)->nodeValue);
+ self::assertTrue($doc->elementExists("$element/text:s"));
+ self::assertTrue($doc->elementExists("$element/text:s[2]"));
+ $element = "$s2s/text:span[8]/text:page-count";
+ self::assertTrue($doc->elementExists($element));
+ }
+
+ /**
+ * Test HideErrors.
+ */
+ public function testHideErrors(): void
+ {
+ $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';
+ self::assertTrue($doc->elementExists($element));
+ self::assertEquals('zxx', $doc->getElementAttribute($element, 'fo:language'));
+ self::assertEquals('zxx', $doc->getElementAttribute($element, 'style:language-asian'));
+ self::assertEquals('zxx', $doc->getElementAttribute($element, 'style:language-complex'));
+ self::assertEquals('none', $doc->getElementAttribute($element, 'fo:country'));
+ self::assertEquals('none', $doc->getElementAttribute($element, 'style:country-asian'));
+ self::assertEquals('none', $doc->getElementAttribute($element, 'style:country-complex'));
+ }
+
+ /**
+ * Test SpaceBeforeAfter.
+ */
+ public function testMultipleSections(): void
+ {
+ $phpWord = new PhpWord();
+ $section = $phpWord->addSection(['paperSize' => 'Letter', 'Orientation' => 'portrait']);
+ $section->addText('This section uses Letter paper in portrait orientation.');
+ $section = $phpWord->addSection(['paperSize' => 'A4', 'Orientation' => 'landscape', 'pageNumberingStart' => '9']);
+ $header = $section->addHeader();
+ $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';
+ self::assertTrue($doc->elementExists($s2a));
+ self::assertTrue($doc->elementExists($s2t));
+
+ $element = "$s2a/style:style[2]";
+ self::assertTrue($doc->elementExists($element));
+ self::assertEquals('SB1', $doc->getElementAttribute($element, 'style:name'));
+ self::assertEquals('Standard1', $doc->getElementAttribute($element, 'style:master-page-name'));
+ $element .= '/style:text-properties';
+ self::assertTrue($doc->elementExists($element));
+ self::assertEquals('none', $doc->getElementAttribute($element, 'text:display'));
+ $element = "$s2a/style:style[3]";
+ self::assertTrue($doc->elementExists($element));
+ self::assertEquals('SB2', $doc->getElementAttribute($element, 'style:name'));
+ self::assertEquals('Standard2', $doc->getElementAttribute($element, 'style:master-page-name'));
+ $elemen2 = "$element/style:paragraph-properties";
+ self::assertEquals('9', $doc->getElementAttribute($elemen2, 'style:page-number'));
+ $element .= '/style:text-properties';
+ self::assertTrue($doc->elementExists($element));
+ self::assertEquals('none', $doc->getElementAttribute($element, 'text:display'));
+
+ $element = "$s2t/text:section[1]";
+ self::assertTrue($doc->elementExists($element));
+ $element .= '/text:p[1]';
+ self::assertEquals('SB1', $doc->getElementAttribute($element, 'text:style-name'));
+ $element = "$s2t/text:section[2]";
+ self::assertTrue($doc->elementExists($element));
+ $element .= '/text:p[1]';
+ self::assertEquals('SB2', $doc->getElementAttribute($element, 'text:style-name'));
+
+ $doc->setDefaultFile('styles.xml');
+ $s2a = '/office:document-styles/office:automatic-styles';
+ self::assertTrue($doc->elementExists($s2a));
+
+ $element = "$s2a/style:page-layout[1]";
+ self::assertTrue($doc->elementExists($element));
+ self::assertEquals('Mpm1', $doc->getElementAttribute($element, 'style:name'));
+ $element .= '/style:page-layout-properties';
+ self::assertTrue($doc->elementExists($element));
+ self::assertEquals('8.5in', $doc->getElementAttribute($element, 'fo:page-width'));
+ self::assertEquals('11in', $doc->getElementAttribute($element, 'fo:page-height'));
+ self::assertEquals('portrait', $doc->getElementAttribute($element, 'style:print-orientation'));
+
+ $element = "$s2a/style:page-layout[2]";
+ self::assertTrue($doc->elementExists($element));
+ self::assertEquals('Mpm2', $doc->getElementAttribute($element, 'style:name'));
+ $element .= '/style:page-layout-properties';
+ self::assertTrue($doc->elementExists($element));
+ self::assertEquals('29.7cm', $doc->getElementAttribute($element, 'fo:page-width'));
+ self::assertEquals('21cm', $doc->getElementAttribute($element, 'fo:page-height'));
+ self::assertEquals('landscape', $doc->getElementAttribute($element, 'style:print-orientation'));
+
+ $s2a = '/office:document-styles/office:master-styles';
+ self::assertTrue($doc->elementExists($s2a));
+ $element = "$s2a/style:master-page[1]";
+ self::assertTrue($doc->elementExists($element));
+ self::assertEquals('Standard1', $doc->getElementAttribute($element, 'style:name'));
+ self::assertEquals('Mpm1', $doc->getElementAttribute($element, 'style:page-layout-name'));
+ $element = "$s2a/style:master-page[2]";
+ self::assertTrue($doc->elementExists($element));
+ self::assertEquals('Standard2', $doc->getElementAttribute($element, 'style:name'));
+ self::assertEquals('Mpm2', $doc->getElementAttribute($element, 'style:page-layout-name'));
+ }
+}
diff --git a/tests/PhpWord/Writer/ODText/StyleTest.php b/tests/PhpWordTests/Writer/ODText/StyleTest.php
similarity index 76%
rename from tests/PhpWord/Writer/ODText/StyleTest.php
rename to tests/PhpWordTests/Writer/ODText/StyleTest.php
index b1bf417d59..21d4c8bb53 100644
--- a/tests/PhpWord/Writer/ODText/StyleTest.php
+++ b/tests/PhpWordTests/Writer/ODText/StyleTest.php
@@ -1,4 +1,5 @@
write();
- $this->assertEquals('', $xmlWriter->getData());
+ self::assertEquals('', $xmlWriter->getData());
}
}
}
diff --git a/tests/PhpWord/Writer/ODTextTest.php b/tests/PhpWordTests/Writer/ODTextTest.php
similarity index 61%
rename from tests/PhpWord/Writer/ODTextTest.php
rename to tests/PhpWordTests/Writer/ODTextTest.php
index a576a68d60..9746791379 100644
--- a/tests/PhpWord/Writer/ODTextTest.php
+++ b/tests/PhpWordTests/Writer/ODTextTest.php
@@ -1,4 +1,5 @@
assertInstanceOf('PhpOffice\\PhpWord\\PhpWord', $object->getPhpWord());
+ self::assertInstanceOf('PhpOffice\\PhpWord\\PhpWord', $object->getPhpWord());
- $this->assertEquals('./', $object->getDiskCachingDirectory());
- foreach (array('Content', 'Manifest', 'Meta', 'Mimetype', 'Styles') as $part) {
- $this->assertInstanceOf(
+ self::assertEquals('./', $object->getDiskCachingDirectory());
+ foreach (['Content', 'Manifest', 'Meta', 'Mimetype', 'Styles'] as $part) {
+ self::assertInstanceOf(
"PhpOffice\\PhpWord\\Writer\\ODText\\Part\\{$part}",
$object->getWriterPart($part)
);
- $this->assertInstanceOf(
+ self::assertInstanceOf(
'PhpOffice\\PhpWord\\Writer\\ODText',
$object->getWriterPart($part)->getParentWriter()
);
@@ -50,29 +52,28 @@ public function testConstruct()
}
/**
- * Construct with null
- *
- * @expectedException \PhpOffice\PhpWord\Exception\Exception
- * @expectedExceptionMessage No PhpWord assigned.
+ * Construct with null.
*/
- public function testConstructWithNull()
+ public function testConstructWithNull(): void
{
+ $this->expectException(\PhpOffice\PhpWord\Exception\Exception::class);
+ $this->expectExceptionMessage('No PhpWord assigned.');
$object = new ODText();
$object->getPhpWord();
}
/**
- * Save
+ * Save.
*/
- public function testSave()
+ public function testSave(): void
{
$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('alignment' => Jc::CENTER));
+ $phpWord->addFontStyle('Font', ['size' => 11]);
+ $phpWord->addParagraphStyle('Paragraph', ['alignment' => Jc::CENTER]);
$section = $phpWord->addSection();
$section->addText('Test 1', 'Font');
$section->addTextBreak();
@@ -91,56 +92,56 @@ public function testSave()
$writer = new ODText($phpWord);
$writer->save($file);
- $this->assertFileExists($file);
+ self::assertFileExists($file);
unlink($file);
}
/**
- * Save php output
+ * Save php output.
*
* @todo Haven't got any method to test this
*/
- public function testSavePhpOutput()
+ public function testSavePhpOutput(): void
{
- $this->setOutputCallback(function () {
- });
$phpWord = new PhpWord();
$section = $phpWord->addSection();
$section->addText('Test');
$writer = new ODText($phpWord);
+ ob_start();
$writer->save('php://output');
- $this->assertNotNull($this->getActualOutput());
+ $contents = ob_get_contents();
+ self::assertTrue(ob_end_clean());
+ self::assertNotEmpty($contents);
}
/**
- * Get writer part return null value
+ * Get writer part return null value.
*/
- public function testGetWriterPartNull()
+ public function testGetWriterPartNull(): void
{
$object = new ODText();
- $this->assertNull($object->getWriterPart('foo'));
+ self::assertNull($object->getWriterPart('foo'));
}
/**
- * Set/get use disk caching
+ * Set/get use disk caching.
*/
- public function testSetGetUseDiskCaching()
+ public function testSetGetUseDiskCaching(): void
{
$object = new ODText();
$object->setUseDiskCaching(true, PHPWORD_TESTS_BASE_DIR);
- $this->assertTrue($object->isUseDiskCaching());
- $this->assertEquals(PHPWORD_TESTS_BASE_DIR, $object->getDiskCachingDirectory());
+ self::assertTrue($object->isUseDiskCaching());
+ self::assertEquals(PHPWORD_TESTS_BASE_DIR, $object->getDiskCachingDirectory());
}
/**
- * Use disk caching exception
- *
- * @expectedException \PhpOffice\PhpWord\Exception\Exception
+ * Use disk caching exception.
*/
- public function testSetUseDiskCachingException()
+ public function testSetUseDiskCachingException(): void
{
- $dir = implode(DIRECTORY_SEPARATOR, array(PHPWORD_TESTS_BASE_DIR, 'foo'));
+ $this->expectException(\PhpOffice\PhpWord\Exception\Exception::class);
+ $dir = implode(DIRECTORY_SEPARATOR, [PHPWORD_TESTS_BASE_DIR, 'foo']);
$object = new ODText();
$object->setUseDiskCaching(true, $dir);
diff --git a/tests/PhpWord/Writer/PDF/DomPDFTest.php b/tests/PhpWordTests/Writer/PDF/DomPDFTest.php
similarity index 61%
rename from tests/PhpWord/Writer/PDF/DomPDFTest.php
rename to tests/PhpWordTests/Writer/PDF/DomPDFTest.php
index bc229d5186..37ea762802 100644
--- a/tests/PhpWord/Writer/PDF/DomPDFTest.php
+++ b/tests/PhpWordTests/Writer/PDF/DomPDFTest.php
@@ -1,4 +1,5 @@
save($file);
- $this->assertFileExists($file);
+ self::assertFileExists($file);
unlink($file);
}
/**
- * Test set/get abstract renderer properties
+ * Test set/get abstract renderer properties.
*/
- public function testSetGetAbstractRendererProperties()
+ public function testSetGetAbstractRendererProperties(): void
{
define('DOMPDF_ENABLE_AUTOLOAD', false);
@@ -64,15 +65,32 @@ public function testSetGetAbstractRendererProperties()
$writer = new PDF(new PhpWord());
$writer->setFont('arial');
- $this->assertEquals('arial', $writer->getFont());
+ self::assertEquals('arial', $writer->getFont());
$writer->setPaperSize();
- $this->assertEquals(9, $writer->getPaperSize());
+ self::assertEquals(9, $writer->getPaperSize());
$writer->setOrientation();
- $this->assertEquals('default', $writer->getOrientation());
+ self::assertEquals('default', $writer->getOrientation());
$writer->setTempDir(Settings::getTempDir());
- $this->assertEquals(Settings::getTempDir(), $writer->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
new file mode 100644
index 0000000000..dc779bd51f
--- /dev/null
+++ b/tests/PhpWordTests/Writer/PDF/MPDFTest.php
@@ -0,0 +1,116 @@
+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);
+ $writer->save($file);
+
+ self::assertFileExists($file);
+
+ unlink($file);
+ }
+
+ public function testEditCallback(): void
+ {
+ $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 cbEditContent(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;
+ }
+
+ /**
+ * 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/PhpWord/Writer/PDF/TCPDFTest.php b/tests/PhpWordTests/Writer/PDF/TCPDFTest.php
similarity index 61%
rename from tests/PhpWord/Writer/PDF/TCPDFTest.php
rename to tests/PhpWordTests/Writer/PDF/TCPDFTest.php
index 6dc8f24cb7..16887507a9 100644
--- a/tests/PhpWord/Writer/PDF/TCPDFTest.php
+++ b/tests/PhpWordTests/Writer/PDF/TCPDFTest.php
@@ -1,4 +1,5 @@
setDefaultParagraphStyle(['spaceBefore' => 0, 'spaceAfter' => 0]);
$section = $phpWord->addSection();
$section->addText('Test 1');
@@ -45,8 +47,23 @@ public function testConstruct()
$writer = new PDF($phpWord);
$writer->save($file);
- $this->assertFileExists($file);
+ self::assertFileExists($file);
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());
+ }
}
diff --git a/tests/PhpWord/Writer/PDFTest.php b/tests/PhpWordTests/Writer/PDFTest.php
similarity index 70%
rename from tests/PhpWord/Writer/PDFTest.php
rename to tests/PhpWordTests/Writer/PDFTest.php
index f699385c8c..b9e31511cf 100644
--- a/tests/PhpWord/Writer/PDFTest.php
+++ b/tests/PhpWordTests/Writer/PDFTest.php
@@ -1,4 +1,5 @@
save($file);
- $this->assertFileExists($file);
+ self::assertFileExists($file);
unlink($file);
}
/**
- * Test construct exception
- *
- * @expectedException \PhpOffice\PhpWord\Exception\Exception
- * @expectedExceptionMessage PDF rendering library or library path has not been defined.
+ * Test construct exception.
*/
- public function testConstructException()
+ 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/Element/TableTest.php b/tests/PhpWordTests/Writer/RTF/Element/TableTest.php
new file mode 100644
index 0000000000..7c1ceac68e
--- /dev/null
+++ b/tests/PhpWordTests/Writer/RTF/Element/TableTest.php
@@ -0,0 +1,170 @@
+write());
+ }
+
+ public function testTable(): void
+ {
+ Settings::setDefaultRtl(false);
+ $parentWriter = new RTF();
+ $element = new 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
new file mode 100644
index 0000000000..2220d93b68
--- /dev/null
+++ b/tests/PhpWordTests/Writer/RTF/Element2Test.php
@@ -0,0 +1,79 @@
+write());
+ }
+
+ public function testTextRun(): void
+ {
+ Settings::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
+ {
+ Settings::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();
+ 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));
+ Settings::setDefaultRtl(null);
+ }
+}
diff --git a/tests/PhpWordTests/Writer/RTF/ElementTest.php b/tests/PhpWordTests/Writer/RTF/ElementTest.php
new file mode 100644
index 0000000000..36504a18f8
--- /dev/null
+++ b/tests/PhpWordTests/Writer/RTF/ElementTest.php
@@ -0,0 +1,219 @@
+write());
+ }
+
+ /**
+ * Test unmatched elements.
+ */
+ public function testUnmatchedElements(): void
+ {
+ $elements = ['Container', 'Text', 'Title', 'Link', 'Image', 'Table', 'Field'];
+ foreach ($elements as $element) {
+ $objectClass = 'PhpOffice\\PhpWord\\Writer\\RTF\\Element\\' . $element;
+ $parentWriter = new RTF();
+ $newElement = new \PhpOffice\PhpWord\Element\PageBreak();
+ $object = new $objectClass($parentWriter, $newElement);
+
+ self::assertEquals('', $object->write());
+ }
+ }
+
+ public function testFilenameField(): void
+ {
+ $parentWriter = new RTF();
+ $element = new \PhpOffice\PhpWord\Element\Field('FILENAME');
+ $field = new 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 RTF\Element\Field($parentWriter, $element);
+
+ self::assertEquals("{\\field{\\*\\fldinst FILENAME \\\\p}{\\fldrslt}}\\par\n", $this->removeCr($field));
+ }
+
+ public function testPageField(): void
+ {
+ $parentWriter = new RTF();
+ $element = new \PhpOffice\PhpWord\Element\Field('PAGE');
+ $field = new RTF\Element\Field($parentWriter, $element);
+
+ self::assertEquals("{\\field{\\*\\fldinst PAGE}{\\fldrslt}}\\par\n", $this->removeCr($field));
+ }
+
+ public function testNumpageField(): void
+ {
+ $parentWriter = new RTF();
+ $element = new \PhpOffice\PhpWord\Element\Field('NUMPAGES');
+ $field = new RTF\Element\Field($parentWriter, $element);
+
+ self::assertEquals("{\\field{\\*\\fldinst NUMPAGES}{\\fldrslt}}\\par\n", $this->removeCr($field));
+ }
+
+ public function testDateField(): void
+ {
+ $parentWriter = new RTF();
+ $element = new \PhpOffice\PhpWord\Element\Field('DATE', ['dateformat' => 'd MM yyyy H:mm:ss']);
+ $field = new RTF\Element\Field($parentWriter, $element);
+
+ self::assertEquals("{\\field{\\*\\fldinst DATE \\\\@ \"d MM yyyy H:mm:ss\"}{\\fldrslt}}\\par\n", $this->removeCr($field));
+ }
+
+ public function testIndexField(): void
+ {
+ $parentWriter = new RTF();
+ $element = new \PhpOffice\PhpWord\Element\Field('INDEX');
+ $field = new RTF\Element\Field($parentWriter, $element);
+
+ self::assertEquals("{}\\par\n", $this->removeCr($field));
+ }
+
+ public function testTable(): void
+ {
+ $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 RTF\Element\Table($parentWriter, $element);
+ $expect = implode("\n", [
+ '\\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',
+ '',
+ ]);
+
+ self::assertEquals($expect, $this->removeCr($table));
+ }
+
+ public function testTextRun(): void
+ {
+ $parentWriter = new RTF();
+ $element = new \PhpOffice\PhpWord\Element\TextRun();
+ $element->addText('Hello ');
+ $element->addText('there.');
+ $textrun = new RTF\Element\TextRun($parentWriter, $element);
+ $expect = "\\pard\\nowidctlpar {{\\cf0\\f0 Hello }{\\cf0\\f0 there.}}\\par\n";
+ self::assertEquals($expect, $this->removeCr($textrun));
+ }
+
+ public function testTextRunParagraphStyle(): void
+ {
+ $parentWriter = new RTF();
+ $element = new \PhpOffice\PhpWord\Element\TextRun(['spaceBefore' => 0, 'spaceAfter' => 0]);
+ $element->addText('Hello ');
+ $element->addText('there.');
+ $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));
+ }
+
+ public function testTitle(): void
+ {
+ $parentWriter = new RTF();
+ $phpWord = new \PhpOffice\PhpWord\PhpWord();
+ $phpWord->addTitleStyle(1, [], ['spaceBefore' => 0, 'spaceAfter' => 0]);
+ $section = $phpWord->addSection();
+ $element = $section->addTitle('First Heading', 1);
+ $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));
+ }
+
+ 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/RTF/HeaderFooterTest.php b/tests/PhpWordTests/Writer/RTF/HeaderFooterTest.php
new file mode 100644
index 0000000000..3b4f86c7d7
--- /dev/null
+++ b/tests/PhpWordTests/Writer/RTF/HeaderFooterTest.php
@@ -0,0 +1,79 @@
+addSection();
+ $section->addText('Doc without header or footer');
+ $contents = $parentWriter->getWriterPart('Document')->write();
+ self::assertEquals(0, preg_match('/\\\\header[rlf]?\\b/', $contents));
+ self::assertEquals(0, preg_match('/\\\\footer[rlf]?\\b/', $contents));
+ self::assertEquals(0, preg_match('/\\\\titlepg\\b/', $contents));
+ self::assertEquals(0, preg_match('/\\\\facingp\\b/', $contents));
+ }
+
+ public function testNoHeaderYesFooter(): void
+ {
+ $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();
+ self::assertEquals(0, preg_match('/\\\\header[rlf]?\\b/', $contents));
+ self::assertEquals(1, preg_match('/\\\\footer[rlf]?\\b/', $contents));
+ self::assertEquals(0, preg_match('/\\\\titlepg\\b/', $contents));
+ self::assertEquals(0, preg_match('/\\\\facingp\\b/', $contents));
+ }
+
+ public function testEvenHeaderFirstFooter(): void
+ {
+ $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();
+ self::assertEquals(1, preg_match('/\\\\headerr\\b/', $contents));
+ self::assertEquals(1, preg_match('/\\\\headerl\\b/', $contents));
+ self::assertEquals(0, preg_match('/\\\\header[f]?\\b/', $contents));
+ self::assertEquals(1, preg_match('/\\\\footerf\\b/', $contents));
+ self::assertEquals(0, preg_match('/\\\\footer[rl]?\\b/', $contents));
+ self::assertEquals(1, preg_match('/\\\\titlepg\\b/', $contents));
+ self::assertEquals(1, preg_match('/\\\\facingp\\b/', $contents));
+ }
+}
diff --git a/tests/PhpWordTests/Writer/RTF/StyleTest.php b/tests/PhpWordTests/Writer/RTF/StyleTest.php
new file mode 100644
index 0000000000..8ba2bcb9c9
--- /dev/null
+++ b/tests/PhpWordTests/Writer/RTF/StyleTest.php
@@ -0,0 +1,183 @@
+write());
+ }
+
+ /**
+ * Test empty styles.
+ */
+ public function testEmptyStyles(): void
+ {
+ $styles = ['Font', 'Paragraph', 'Section', 'Tab', 'Indentation'];
+ foreach ($styles as $style) {
+ $objectClass = 'PhpOffice\\PhpWord\\Writer\\RTF\\Style\\' . $style;
+ $object = new $objectClass();
+
+ self::assertEquals('', $object->write());
+ }
+ }
+
+ public function testBorderWithNonRegisteredColors(): void
+ {
+ $border = new Border();
+ $border->setSizes([1, 2, 3, 4]);
+ $border->setColors(['#FF0000', '#FF0000', '#FF0000', '#FF0000']);
+ $border->setSizes([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 ';
+
+ self::assertEquals($expected, $content);
+ }
+
+ public function testIndentation(): void
+ {
+ $indentation = new \PhpOffice\PhpWord\Style\Indentation();
+ $indentation->setLeft(1);
+ $indentation->setRight(2);
+ $indentation->setFirstLine(3);
+
+ $indentWriter = new RTF\Style\Indentation($indentation);
+ $indentWriter->setParentWriter(new RTF());
+ $result = $indentWriter->write();
+
+ Assert::assertEquals('\fi3\li1\ri2 ', $result);
+ }
+
+ public function testRightTab(): void
+ {
+ $tabRight = new \PhpOffice\PhpWord\Style\Tab();
+ $tabRight->setType(\PhpOffice\PhpWord\Style\Tab::TAB_STOP_RIGHT);
+ $tabRight->setPosition(5);
+
+ $tabWriter = new RTF\Style\Tab($tabRight);
+ $tabWriter->setParentWriter(new RTF());
+ $result = $tabWriter->write();
+
+ Assert::assertEquals('\tqr\tx5', $result);
+ }
+
+ public function testCenterTab(): void
+ {
+ $tabRight = new \PhpOffice\PhpWord\Style\Tab();
+ $tabRight->setType(\PhpOffice\PhpWord\Style\Tab::TAB_STOP_CENTER);
+
+ $tabWriter = new RTF\Style\Tab($tabRight);
+ $tabWriter->setParentWriter(new RTF());
+ $result = $tabWriter->write();
+
+ Assert::assertEquals('\tqc\tx0', $result);
+ }
+
+ public function testDecimalTab(): void
+ {
+ $tabRight = new \PhpOffice\PhpWord\Style\Tab();
+ $tabRight->setType(\PhpOffice\PhpWord\Style\Tab::TAB_STOP_DECIMAL);
+
+ $tabWriter = new RTF\Style\Tab($tabRight);
+ $tabWriter->setParentWriter(new RTF());
+ $result = $tabWriter->write();
+
+ Assert::assertEquals('\tqdec\tx0', $result);
+ }
+
+ public function testRTL(): void
+ {
+ $parentWriter = new RTF();
+ $element = new \PhpOffice\PhpWord\Element\Text('אב גד', ['RTL' => true]);
+ $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));
+ }
+
+ public function testRTL2(): void
+ {
+ Settings::setDefaultRtl(true);
+ $parentWriter = new RTF();
+ $element = new \PhpOffice\PhpWord\Element\Text('אב גד');
+ $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));
+ }
+
+ public function testPageBreakLineHeight(): void
+ {
+ $parentWriter = new RTF();
+ $element = new \PhpOffice\PhpWord\Element\Text('New page', null, ['lineHeight' => 1.08, 'pageBreakBefore' => true]);
+ $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));
+ }
+
+ 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 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();
+ $phpword = new \PhpOffice\PhpWord\PhpWord();
+ $section = $phpword->addSection(['pageNumberingStart' => 5]);
+ $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);
+ $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";
+ self::assertEquals($expect, $wstyle);
+ }
+}
diff --git a/tests/PhpWord/Writer/RTFTest.php b/tests/PhpWordTests/Writer/RTFTest.php
similarity index 69%
rename from tests/PhpWord/Writer/RTFTest.php
rename to tests/PhpWordTests/Writer/RTFTest.php
index 010720bd12..4f9f8944ac 100644
--- a/tests/PhpWord/Writer/RTFTest.php
+++ b/tests/PhpWordTests/Writer/RTFTest.php
@@ -1,4 +1,5 @@
assertInstanceOf('PhpOffice\\PhpWord\\PhpWord', $object->getPhpWord());
+ self::assertInstanceOf('PhpOffice\\PhpWord\\PhpWord', $object->getPhpWord());
}
/**
- * Construct with null
- *
- * @expectedException \PhpOffice\PhpWord\Exception\Exception
- * @expectedExceptionMessage No PhpWord assigned.
+ * Construct with null.
*/
- public function testConstructWithNull()
+ public function testConstructWithNull(): void
{
+ $this->expectException(\PhpOffice\PhpWord\Exception\Exception::class);
+ $this->expectExceptionMessage('No PhpWord assigned.');
$object = new RTF();
$object->getPhpWord();
}
/**
- * Save
+ * Save.
*/
- public function testSave()
+ public function testSave(): void
{
$imageSrc = __DIR__ . '/../_files/images/PhpWord.png';
$objectSrc = __DIR__ . '/../_files/documents/sheet.xls';
@@ -61,21 +62,21 @@ public function testSave()
$phpWord = new PhpWord();
$phpWord->addFontStyle(
'Font',
- array('name' => 'Verdana', 'size' => 11, 'color' => 'FF0000', 'fgColor' => '00FF00')
+ ['name' => 'Verdana', 'size' => 11, 'color' => 'FF0000', 'fgColor' => '00FF00']
);
- $phpWord->addParagraphStyle('Paragraph', array('alignment' => Jc::CENTER));
+ $phpWord->addParagraphStyle('Paragraph', ['alignment' => Jc::CENTER]);
$section = $phpWord->addSection();
$section->addText(htmlspecialchars('Test 1', ENT_COMPAT, 'UTF-8'), 'Font', 'Paragraph');
$section->addTextBreak();
- $section->addText(htmlspecialchars('Test 2', ENT_COMPAT, 'UTF-8'), array('name' => 'Tahoma', 'bold' => true, 'italic' => true));
+ $section->addText(htmlspecialchars('Test 2', ENT_COMPAT, 'UTF-8'), ['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
$table = $section->addTable();
- $table->addRow()->addCell(null, array('vMerge' => 'restart'))->addText('Test');
- $table->addRow()->addCell(null, array('vMerge' => 'continue'))->addText('Test');
+ $table->addRow()->addCell(null, ['vMerge' => 'restart'])->addText('Test');
+ $table->addRow()->addCell(null, ['vMerge' => 'continue'])->addText('Test');
// Nested table
$cell = $section->addTable()->addRow()->addCell();
@@ -92,25 +93,26 @@ public function testSave()
$writer = new RTF($phpWord);
$writer->save($file);
- $this->assertFileExists($file);
+ self::assertFileExists($file);
@unlink($file);
}
/**
- * Save
+ * Save.
*
* @todo Haven't got any method to test this
*/
- public function testSavePhpOutput()
+ public function testSavePhpOutput(): void
{
- $this->setOutputCallback(function () {
- });
$phpWord = new PhpWord();
$section = $phpWord->addSection();
$section->addText(htmlspecialchars('Test', ENT_COMPAT, 'UTF-8'));
$writer = new RTF($phpWord);
+ ob_start();
$writer->save('php://output');
- $this->assertNotNull($this->getActualOutput());
+ $contents = ob_get_contents();
+ self::assertTrue(ob_end_clean());
+ self::assertNotEmpty($contents);
}
}
diff --git a/tests/PhpWordTests/Writer/Word2007/Element/ChartTest.php b/tests/PhpWordTests/Writer/Word2007/Element/ChartTest.php
new file mode 100644
index 0000000000..4951da39ce
--- /dev/null
+++ b/tests/PhpWordTests/Writer/Word2007/Element/ChartTest.php
@@ -0,0 +1,242 @@
+outputEscapingEnabled = Settings::isOutputEscapingEnabled();
+ }
+
+ /**
+ * Executed after each method of the class.
+ */
+ protected function tearDown(): void
+ {
+ Settings::setOutputEscapingEnabled($this->outputEscapingEnabled);
+ TestHelperDOCX::clear();
+ }
+
+ /**
+ * Test chart elements.
+ */
+ public function testChartElements(): void
+ {
+ $phpWord = new PhpWord();
+ $section = $phpWord->addSection();
+ $style = [
+ 'width' => 5000000,
+ 'height' => 5000000,
+ 'showAxisLabels' => true,
+ 'showGridX' => true,
+ 'showGridY' => true,
+ 'showLegend' => false,
+ ];
+
+ $chartTypes = ['pie', 'doughnut', 'bar', 'line', 'area', 'scatter', 'radar'];
+ $categories = ['A', 'B', 'C', 'D', 'E'];
+ $series1 = [1, 3, 2, 5, 4];
+ foreach ($chartTypes as $chartType) {
+ $section->addChart($chartType, $categories, $series1, $style);
+ }
+ $colorArray = ['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 - 1], $doc->getElementAttribute($element, 'val'), "bar chart idx=$idx");
+ }
+ }
+
+ public function testChartEscapingEnabled(): void
+ {
+ Settings::setOutputEscapingEnabled(true);
+ $phpWord = new PhpWord();
+ $section = $phpWord->addSection();
+ $style = [
+ 'width' => 5000000,
+ 'height' => 5000000,
+ 'showAxisLabels' => true,
+ 'showGridX' => true,
+ 'showGridY' => true,
+ 'showLegend' => false,
+ 'valueAxisTitle' => 'Values',
+ ];
+ $categories = ['A&B', 'C', 'E', 'F', 'G'];
+ $series1 = [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(): void
+ {
+ Settings::setOutputEscapingEnabled(false);
+ $phpWord = new PhpWord();
+ $section = $phpWord->addSection();
+ $style = [
+ 'width' => 5000000,
+ 'height' => 5000000,
+ 'showAxisLabels' => true,
+ 'showGridX' => true,
+ 'showGridY' => true,
+ 'showLegend' => false,
+ 'valueAxisTitle' => 'Values',
+ ];
+ $categories = ['A&B', 'C<D>', 'E', 'F', 'G'];
+ $series1 = [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(): void
+ {
+ $phpWord = new PhpWord();
+ $section = $phpWord->addSection();
+ $style = [
+ 'width' => 5000000,
+ 'height' => 5000000,
+ 'showAxisLabels' => true,
+ 'showGridX' => true,
+ 'showGridY' => true,
+ 'showLegend' => false,
+ 'valueAxisTitle' => 'Values',
+ ];
+ $chartType = 'line';
+ $categories = ['A', 'B', 'C', 'D', 'E'];
+ $series1 = [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(): void
+ {
+ $phpWord = new PhpWord();
+ $section = $phpWord->addSection();
+ $style = [
+ 'width' => 5000000,
+ 'height' => 5000000,
+ 'showAxisLabels' => false,
+ 'showGridX' => true,
+ 'showGridY' => true,
+ 'showLegend' => false,
+ 'valueAxisTitle' => 'Values',
+ ];
+ $chartType = 'line';
+ $categories = ['A', 'B', 'C', 'D', 'E'];
+ $series1 = [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/PhpWordTests/Writer/Word2007/Element/FieldTest.php b/tests/PhpWordTests/Writer/Word2007/Element/FieldTest.php
new file mode 100644
index 0000000000..d3128e8007
--- /dev/null
+++ b/tests/PhpWordTests/Writer/Word2007/Element/FieldTest.php
@@ -0,0 +1,74 @@
+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'));
+ }
+}
diff --git a/tests/PhpWordTests/Writer/Word2007/Element/FormFieldTest.php b/tests/PhpWordTests/Writer/Word2007/Element/FormFieldTest.php
new file mode 100644
index 0000000000..52861900e7
--- /dev/null
+++ b/tests/PhpWordTests/Writer/Word2007/Element/FormFieldTest.php
@@ -0,0 +1,71 @@
+addSection();
+
+ $section->addFormField('textinput')->setName('MyTextBox');
+ $section->addFormField('checkbox')->setDefault(true)->setValue('Your name');
+ $section->addFormField('checkbox')->setDefault(true);
+ $section->addFormField('dropdown')->setEntries(['Choice 1', 'Choice 2', 'Choice 3', '']);
+
+ $doc = TestHelperDOCX::getDocument($phpWord);
+
+ $path = '/w:document/w:body/w:p[1]/w:r/w:fldChar/w:ffData';
+ self::assertTrue($doc->elementExists("$path/w:textInput"));
+ self::assertEquals('MyTextBox', $doc->getElementAttribute("$path/w:name", 'w:val'));
+
+ $path = '/w:document/w:body/w:p[2]/w:r/w:fldChar/w:ffData';
+ self::assertTrue($doc->elementExists("$path/w:checkBox"));
+ $path = '/w:document/w:body/w:p[2]/w:r[4]/w:t';
+ self::assertEquals('Your name', $doc->getElement($path)->textContent);
+
+ $path = '/w:document/w:body/w:p[3]/w:r/w:fldChar/w:ffData';
+ self::assertTrue($doc->elementExists("$path/w:checkBox"));
+
+ $path = '/w:document/w:body/w:p[4]/w:r/w:fldChar/w:ffData/w:ddList';
+ self::assertTrue($doc->elementExists($path));
+ self::assertEquals('Choice 1', $doc->getElementAttribute("$path/w:listEntry[1]", 'w:val'));
+ self::assertEquals('Choice 2', $doc->getElementAttribute("$path/w:listEntry[2]", 'w:val'));
+ self::assertEquals('Choice 3', $doc->getElementAttribute("$path/w:listEntry[3]", 'w:val'));
+ self::assertEquals('', trim($doc->getElementAttribute("$path/w:listEntry[4]", 'w:val'), ' '));
+ }
+}
diff --git a/tests/PhpWordTests/Writer/Word2007/Element/FormulaTest.php b/tests/PhpWordTests/Writer/Word2007/Element/FormulaTest.php
new file mode 100644
index 0000000000..dc0bd19e22
--- /dev/null
+++ b/tests/PhpWordTests/Writer/Word2007/Element/FormulaTest.php
@@ -0,0 +1,73 @@
+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/Element/TOCTest.php b/tests/PhpWordTests/Writer/Word2007/Element/TOCTest.php
new file mode 100644
index 0000000000..66778a41ec
--- /dev/null
+++ b/tests/PhpWordTests/Writer/Word2007/Element/TOCTest.php
@@ -0,0 +1,89 @@
+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);
+ }
+
+ public function testWriteTitleWithoutpageNumber(): void
+ {
+ $phpWord = new PhpWord();
+
+ $section = $phpWord->addSection();
+ $section->addTOC();
+
+ $staticHtml = '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.
+ 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.
';
+
+ //more than one title and random text for create more than one page
+ for ($i = 1; $i <= 10; ++$i) {
+ $section->addTitle('Title ' . $i, 1);
+ \PhpOffice\PhpWord\Shared\Html::addHtml($section, $staticHtml, 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);
+ }
+ }
+}
diff --git a/tests/PhpWordTests/Writer/Word2007/Element/TableTest.php b/tests/PhpWordTests/Writer/Word2007/Element/TableTest.php
new file mode 100644
index 0000000000..8b9e5efee3
--- /dev/null
+++ b/tests/PhpWordTests/Writer/Word2007/Element/TableTest.php
@@ -0,0 +1,148 @@
+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');
+ }
+}
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 @@
+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"',
+ ],
+ ];
+ }
+}
diff --git a/tests/PhpWordTests/Writer/Word2007/Element/TitleTest.php b/tests/PhpWordTests/Writer/Word2007/Element/TitleTest.php
new file mode 100644
index 0000000000..1d62ffa964
--- /dev/null
+++ b/tests/PhpWordTests/Writer/Word2007/Element/TitleTest.php
@@ -0,0 +1,97 @@
+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
new file mode 100644
index 0000000000..c22994607b
--- /dev/null
+++ b/tests/PhpWordTests/Writer/Word2007/ElementTest.php
@@ -0,0 +1,667 @@
+write();
+
+ self::assertEquals('', $xmlWriter->getData());
+ }
+ }
+
+ /**
+ * Test line element.
+ */
+ public function testLineElement(): void
+ {
+ $phpWord = new PhpWord();
+ $section = $phpWord->addSection();
+
+ $section->addLine(['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';
+ self::assertTrue($doc->elementExists($element));
+ }
+
+ /**
+ * Test bookmark element.
+ */
+ public function testBookmark(): void
+ {
+ $phpWord = new PhpWord();
+ $section = $phpWord->addSection();
+
+ $section->addBookmark('test_bookmark');
+ $doc = TestHelperDOCX::getDocument($phpWord);
+
+ $element = '/w:document/w:body/w:bookmarkStart';
+ self::assertTrue($doc->elementExists($element));
+ self::assertEquals('test_bookmark', $doc->getElementAttribute($element, 'w:name'));
+
+ $element = '/w:document/w:body/w:bookmarkEnd';
+ self::assertTrue($doc->elementExists($element));
+ }
+
+ /**
+ * Test link element.
+ */
+ public function testLinkElement(): void
+ {
+ $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';
+ self::assertTrue($doc->elementExists($element));
+
+ $element = '/w:document/w:body/w:p[2]/w:hyperlink/w:r/w:t';
+ self::assertTrue($doc->elementExists($element));
+ self::assertEquals('internal_link', $doc->getElementAttribute('/w:document/w:body/w:p[2]/w:hyperlink', 'w:anchor'));
+ }
+
+ /**
+ * Basic test for table element.
+ */
+ public function testTableElements(): void
+ {
+ $phpWord = new PhpWord();
+ $section = $phpWord->addSection();
+
+ $table = $section->addTable(['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';
+ self::assertTrue($doc->elementExists($tableRootElement . '/w:tblGrid/w:gridCol'));
+ self::assertTrue($doc->elementExists($tableRootElement . '/w:tblPr/w:jc'));
+ self::assertEquals('center', $doc->getElementAttribute($tableRootElement . '/w:tblPr/w:jc', 'w:val'));
+ }
+
+ /**
+ * Tests that the style name gets added.
+ */
+ public function testTableWithStyleName(): void
+ {
+ $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';
+ self::assertTrue($doc->elementExists($tableRootElement . '/w:tblPr/w:tblStyle'));
+ self::assertEquals('my_predefined_style', $doc->getElementAttribute($tableRootElement . '/w:tblPr/w:tblStyle', 'w:val'));
+ }
+
+ /**
+ * Test shape elements.
+ */
+ public function testShapeElements(): void
+ {
+ $phpWord = new PhpWord();
+ $section = $phpWord->addSection();
+
+ // Arc
+ $section->addShape(
+ 'arc',
+ [
+ 'points' => '-90 20',
+ 'frame' => ['width' => 120, 'height' => 120],
+ 'outline' => ['color' => '#333333', 'weight' => 2, 'startArrow' => 'oval', 'endArrow' => 'open'],
+ ]
+ );
+
+ // Curve
+ $section->addShape(
+ 'curve',
+ [
+ 'points' => '1,100 200,1 1,50 200,50', 'connector' => 'elbow',
+ 'outline' => [
+ 'color' => '#66cc00',
+ 'weight' => 2,
+ 'dash' => 'dash',
+ 'startArrow' => 'diamond',
+ 'endArrow' => 'block',
+ ],
+ ]
+ );
+
+ // Line
+ $section->addShape(
+ 'line',
+ [
+ 'points' => '1,1 150,30',
+ 'outline' => [
+ 'color' => '#cc00ff',
+ 'line' => 'thickThin',
+ 'weight' => 3,
+ 'startArrow' => 'oval',
+ 'endArrow' => 'classic',
+ 'endCap' => 'round',
+ ],
+ ]
+ );
+
+ // Polyline
+ $section->addShape(
+ 'polyline',
+ [
+ '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->addShape(
+ 'rect',
+ [
+ 'roundness' => 0.2,
+ 'frame' => ['width' => 100, 'height' => 100, 'left' => 1, 'top' => 1],
+ 'fill' => ['color' => '#FFCC33'],
+ 'outline' => ['color' => '#990000', 'weight' => 1],
+ 'shadow' => ['color' => '#EEEEEE', 'offset' => '3pt,3pt'],
+ ]
+ );
+
+ // Oval
+ $section->addShape(
+ 'oval',
+ [
+ 'frame' => ['width' => 100, 'height' => 70, 'left' => 1, 'top' => 1],
+ 'fill' => ['color' => '#33CC99'],
+ 'outline' => ['color' => '#333333', 'weight' => 2],
+ 'extrusion' => ['type' => 'perspective', 'color' => '#EEEEEE'],
+ ]
+ );
+
+ $doc = TestHelperDOCX::getDocument($phpWord);
+
+ $elements = ['arc', 'curve', 'line', 'polyline', 'roundrect', 'oval'];
+ foreach ($elements as $element) {
+ $path = "/w:document/w:body/w:p/w:r/w:pict/v:{$element}";
+ self::assertTrue($doc->elementExists($path));
+ }
+ }
+
+ // testChartElements moved to Writer/Word2007/Element/ChartTest
+
+ public function testFieldElement(): void
+ {
+ $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('STYLEREF', ['StyleIdentifier' => 'Heading 1']);
+ $doc = TestHelperDOCX::getDocument($phpWord);
+
+ $element = '/w:document/w:body/w:p/w:r/w:instrText';
+ self::assertTrue($doc->elementExists($element));
+ self::assertEquals(' INDEX \\c "3" ', $doc->getElement($element)->textContent);
+ }
+
+ public function testUnstyledFieldElement(): void
+ {
+ $phpWord = new PhpWord();
+ $phpWord->addFontStyle('h1', ['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';
+ self::assertTrue($doc->elementExists($element));
+ self::assertEquals(' PAGE ', $doc->getElement($element)->textContent);
+ $sty = '/w:document/w:body/w:p/w:r[2]/w:rPr';
+ self::assertFalse($doc->elementExists($sty));
+ }
+
+ public function testStyledFieldElement(): void
+ {
+ $phpWord = new PhpWord();
+ $stnam = 'h1';
+ $phpWord->addFontStyle($stnam, ['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';
+ self::assertTrue($doc->elementExists($element));
+ self::assertEquals(' PAGE ', $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 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();
+ $section = $phpWord->addSection();
+
+ $text = new TextRun();
+ $text->addText('test string', ['bold' => true]);
+
+ $section->addField('XE', [], ['Bold', 'Italic'], $text);
+ $doc = TestHelperDOCX::getDocument($phpWord);
+
+ $element = '/w:document/w:body/w:p/w:r[2]/w:instrText';
+ self::assertTrue($doc->elementExists($element));
+ self::assertEquals(' XE "', $doc->getElement($element)->textContent);
+
+ $element = '/w:document/w:body/w:p/w:r[3]/w:rPr/w:b';
+ self::assertTrue($doc->elementExists($element));
+
+ $element = '/w:document/w:body/w:p/w:r[3]/w:t';
+ self::assertTrue($doc->elementExists($element));
+ self::assertEquals('test string', $doc->getElement($element)->textContent);
+
+ $element = '/w:document/w:body/w:p/w:r[4]/w:instrText';
+ self::assertTrue($doc->elementExists($element));
+ self::assertEquals('"\\b \\i ', $doc->getElement($element)->textContent);
+ }
+
+ /**
+ * Test writing the macrobutton field.
+ */
+ public function testMacroButtonField(): void
+ {
+ $phpWord = new PhpWord();
+ $section = $phpWord->addSection();
+
+ $macroText = new TextRun();
+ $macroText->addText('Double click', ['bold' => true]);
+ $macroText->addText(' to ');
+ $macroText->addText('zoom to 100%', ['italic' => true]);
+
+ $section->addField('MACROBUTTON', ['macroname' => 'Zoom100'], [], $macroText);
+ $section->addField('MACROBUTTON', ['macroname' => 'Zoom100'], [], 'double click to zoom');
+ $doc = TestHelperDOCX::getDocument($phpWord);
+
+ $element = '/w:document/w:body/w:p[1]/w:r[2]/w:instrText';
+ self::assertTrue($doc->elementExists($element));
+ self::assertEquals(' MACROBUTTON Zoom100 ', $doc->getElement($element)->textContent);
+
+ $element = '/w:document/w:body/w:p[1]/w:r[3]/';
+ self::assertTrue($doc->elementExists($element . 'w:t'));
+ self::assertEquals('Double click', $doc->getElement($element . 'w:t')->textContent);
+ self::assertTrue($doc->elementExists($element . 'w:rPr/w:b'));
+
+ $element = '/w:document/w:body/w:p[2]/w:r[2]/w:instrText';
+ self::assertTrue($doc->elementExists($element));
+ self::assertEquals(' MACROBUTTON Zoom100 double click to zoom ', $doc->getElement($element)->textContent);
+ }
+
+ // testFormFieldElements moved to Writer/Word2007/Element/FormFieldTest
+
+ /**
+ * Test SDT elements.
+ */
+ public function testSDTElements(): void
+ {
+ $phpWord = new PhpWord();
+ $section = $phpWord->addSection();
+
+ $section->addSDT('comboBox')->setListItems(['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);
+
+ $path = '/w:document/w:body/w:p';
+
+ self::assertTrue($doc->elementExists($path . '[1]/w:sdt/w:sdtContent/w:r/w:t'));
+ self::assertEquals('select value', $doc->getElement($path . '[1]/w:sdt/w:sdtContent/w:r/w:t')->nodeValue);
+ self::assertTrue($doc->elementExists($path . '[1]/w:sdt/w:sdtPr/w:comboBox'));
+ self::assertTrue($doc->elementExists($path . '[1]/w:sdt/w:sdtPr/w:comboBox/w:listItem'));
+ self::assertEquals('1', $doc->getElementAttribute($path . '[1]/w:sdt/w:sdtPr/w:comboBox/w:listItem[1]', 'w:value'));
+ self::assertEquals('Choice 1', $doc->getElementAttribute($path . '[1]/w:sdt/w:sdtPr/w:comboBox/w:listItem[1]', 'w:displayText'));
+
+ self::assertTrue($doc->elementExists($path . '[2]/w:sdt/w:sdtPr/w:dropDownList'));
+ self::assertFalse($doc->elementExists($path . '[2]/w:sdt/w:sdtPr/w:alias'));
+
+ self::assertTrue($doc->elementExists($path . '[3]/w:sdt/w:sdtPr/w:date'));
+ self::assertTrue($doc->elementExists($path . '[3]/w:sdt/w:sdtPr/w:alias'));
+ self::assertTrue($doc->elementExists($path . '[3]/w:sdt/w:sdtPr/w:tag'));
+
+ self::assertTrue($doc->elementExists($path . '[4]/w:sdt/w:sdtPr/w:text'));
+ }
+
+ /**
+ * Test Comment element.
+ */
+ public function testCommentWithoutEndElement(): void
+ {
+ $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);
+ self::assertTrue($doc->elementExists('/w:document/w:body/w:p/w:commentRangeStart'));
+ self::assertTrue($doc->elementExists('/w:document/w:body/w:p/w:commentRangeEnd'));
+ self::assertTrue($doc->elementExists('/w:document/w:body/w:p/w:r/w:commentReference'));
+ }
+
+ /**
+ * Test Comment element.
+ */
+ public function testCommentWithEndElement(): void
+ {
+ $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);
+ self::assertTrue($doc->elementExists('/w:document/w:body/w:p/w:commentRangeStart'));
+ self::assertTrue($doc->elementExists('/w:document/w:body/w:p/w:commentRangeEnd'));
+ self::assertTrue($doc->elementExists('/w:document/w:body/w:p/w:r/w:commentReference'));
+ }
+
+ /**
+ * Test Track changes.
+ */
+ public function testTrackChange(): void
+ {
+ $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);
+
+ self::assertTrue($doc->elementExists('/w:document/w:body/w:p/w:ins/w:r'));
+ self::assertEquals('author name', $doc->getElementAttribute('/w:document/w:body/w:p/w:ins', 'w:author'));
+ self::assertTrue($doc->elementExists('/w:document/w:body/w:p/w:del/w:r/w:delText'));
+ }
+
+ /**
+ * Test correct writing of text with ampersant in it.
+ */
+ public function testTextWithAmpersant(): void
+ {
+ \PhpOffice\PhpWord\Settings::setOutputEscapingEnabled(true);
+ $phpWord = new PhpWord();
+ $section = $phpWord->addSection();
+ $section->addText('this text contains an & (ampersant)');
+
+ $doc = TestHelperDOCX::getDocument($phpWord);
+ self::assertTrue($doc->elementExists('/w:document/w:body/w:p/w:r/w:t'));
+ self::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(): void
+ {
+ $phpWord = new PhpWord();
+ $phpWord->addParagraphStyle('MyParagraphStyle', ['spaceBefore' => 400]);
+
+ $section = $phpWord->addSection();
+ $listItemRun = $section->addListItemRun(0, null, 'MyParagraphStyle');
+ $listItemRun->addText('List item');
+ $listItemRun->addText(' in bold', ['bold' => true]);
+
+ $doc = TestHelperDOCX::getDocument($phpWord);
+ self::assertFalse($doc->elementExists('/w:document/w:body/w:p/w:pPr/w:pPr'));
+ self::assertTrue($doc->elementExists('/w:document/w:body/w:p/w:pPr/w:pStyle'));
+ self::assertEquals('List item', $doc->getElement('/w:document/w:body/w:p/w:r[1]/w:t')->nodeValue);
+ 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
+ );
+ }
+}
diff --git a/tests/PhpWordTests/Writer/Word2007/Part/AbstractPartTest.php b/tests/PhpWordTests/Writer/Word2007/Part/AbstractPartTest.php
new file mode 100644
index 0000000000..1bcd43f50e
--- /dev/null
+++ b/tests/PhpWordTests/Writer/Word2007/Part/AbstractPartTest.php
@@ -0,0 +1,72 @@
+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());
+ }
+
+ /**
+ * covers ::getParentWriter.
+ */
+ 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 {
+ /** @var Word2007\Part\AbstractPart $stub */
+ $stub = new class() extends Word2007\Part\AbstractPart {
+ public function write(): string
+ {
+ return '';
+ }
+ };
+ }
+ $stub->getParentWriter();
+ }
+}
diff --git a/tests/PhpWord/Writer/Word2007/Part/CommentsTest.php b/tests/PhpWordTests/Writer/Word2007/Part/CommentsTest.php
similarity index 67%
rename from tests/PhpWord/Writer/Word2007/Part/CommentsTest.php
rename to tests/PhpWordTests/Writer/Word2007/Part/CommentsTest.php
index 0233abdf2e..8f8c8240a9 100644
--- a/tests/PhpWord/Writer/Word2007/Part/CommentsTest.php
+++ b/tests/PhpWordTests/Writer/Word2007/Part/CommentsTest.php
@@ -1,4 +1,5 @@
addText('Test');
$phpWord = new PhpWord();
@@ -50,11 +52,11 @@ public function testWriteComments()
$path = '/w:comments/w:comment';
$file = 'word/comments.xml';
- $this->assertTrue($doc->elementExists($path, $file));
+ self::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'));
+ self::assertNotNull($element->getAttribute('w:id'));
+ self::assertEquals('Authors name', $element->getAttribute('w:author'));
+ self::assertEquals('my_initials', $element->getAttribute('w:initials'));
}
}
diff --git a/tests/PhpWord/Writer/Word2007/Part/DocumentTest.php b/tests/PhpWordTests/Writer/Word2007/Part/DocumentTest.php
similarity index 57%
rename from tests/PhpWord/Writer/Word2007/Part/DocumentTest.php
rename to tests/PhpWordTests/Writer/Word2007/Part/DocumentTest.php
index b35f932770..d1f5b2585d 100644
--- a/tests/PhpWord/Writer/Word2007/Part/DocumentTest.php
+++ b/tests/PhpWordTests/Writer/Word2007/Part/DocumentTest.php
@@ -1,22 +1,22 @@
getDocInfo();
@@ -54,23 +54,23 @@ public function testWriteCustomProps()
$docInfo->setCustomProperty('key3', 3);
$docInfo->setCustomProperty('key4', 4.4);
$docInfo->setCustomProperty('key5', 'value5');
- $docInfo->setCustomProperty('key6', new \DateTime());
+ $docInfo->setCustomProperty('key6', new DateTime());
$docInfo->setCustomProperty('key7', time(), DocInfo::PROPERTY_TYPE_DATE);
$doc = TestHelperDOCX::getDocument($phpWord);
- $this->assertNotNull($doc);
+ 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'));
}
/**
- * Write end section page numbering
+ * Write end section page numbering.
*/
- public function testWriteEndSectionPageNumbering()
+ public function testWriteEndSectionPageNumbering(): void
{
$phpWord = new PhpWord();
$section = $phpWord->addSection();
@@ -85,13 +85,13 @@ public function testWriteEndSectionPageNumbering()
$doc = TestHelperDOCX::getDocument($phpWord);
$element = $doc->getElement('/w:document/w:body/w:sectPr/w:pgNumType');
- $this->assertEquals(2, $element->getAttribute('w:start'));
+ self::assertEquals(2, $element->getAttribute('w:start'));
}
/**
- * Write section footnote properties
+ * Write section footnote properties.
*/
- public function testSectionFootnoteProperties()
+ public function testSectionFootnoteProperties(): void
{
$properties = new FootnoteProperties();
$properties->setPos(FootnoteProperties::POSITION_DOC_END);
@@ -106,28 +106,28 @@ public function testSectionFootnoteProperties()
$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'));
+ self::assertEquals(FootnoteProperties::POSITION_DOC_END, $element->getAttribute('w:val'));
$element = $doc->getElement('/w:document/w:body/w:sectPr/w:footnotePr/w:numFmt');
- $this->assertEquals(NumberFormat::LOWER_ROMAN, $element->getAttribute('w:val'));
+ self::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'));
+ self::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'));
+ self::assertEquals(FootnoteProperties::RESTART_NUMBER_EACH_PAGE, $element->getAttribute('w:val'));
}
/**
- * Write elements
+ * Write elements.
*/
- public function testElements()
+ public function testElements(): void
{
$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, ['color' => '333333', 'bold' => true]);
+ $phpWord->addTitleStyle(2, ['color' => '666666']);
$section = $phpWord->addSection();
$section->addTOC();
$section->addPageBreak();
@@ -140,109 +140,109 @@ public function testElements()
$section = $phpWord->addSection();
$section->addTitle('Title 2', 2);
$section->addObject($objectSrc);
- $section->addTextBox(array());
+ $section->addTextBox([]);
$section->addTextBox(
- array(
- 'wrappingStyle' => 'square',
- 'positioning' => 'relative',
+ [
+ 'wrappingStyle' => 'square',
+ 'positioning' => 'relative',
'posHorizontalRel' => 'margin',
- 'posVerticalRel' => 'margin',
- 'innerMargin' => 10,
- 'borderSize' => 1,
- 'borderColor' => '#FF0',
- )
+ 'posVerticalRel' => 'margin',
+ 'innerMargin' => 10,
+ 'borderSize' => 1,
+ 'borderColor' => '#FF0',
+ ]
);
- $section->addTextBox(array('wrappingStyle' => 'tight', 'positioning' => 'absolute', 'alignment' => Jc::CENTER));
+ $section->addTextBox(['wrappingStyle' => 'tight', 'positioning' => 'absolute', 'alignment' => Jc::CENTER]);
$section->addListItemRun()->addText('List item run 1');
$section->addField(
'DATE',
- array('dateformat' => 'dddd d MMMM yyyy H:mm:ss'),
- array('PreserveFormat', 'LunarCalendar')
+ ['dateformat' => 'dddd d MMMM yyyy H:mm:ss'],
+ ['PreserveFormat', 'LunarCalendar']
);
$section->addField(
'DATE',
- array('dateformat' => 'dddd d MMMM yyyy H:mm:ss'),
- array('PreserveFormat', 'SakaEraCalendar')
+ ['dateformat' => 'dddd d MMMM yyyy H:mm:ss'],
+ ['PreserveFormat', 'SakaEraCalendar']
);
$section->addField(
'DATE',
- array('dateformat' => 'dddd d MMMM yyyy H:mm:ss'),
- array('PreserveFormat', 'LastUsedFormat')
+ ['dateformat' => 'dddd d MMMM yyyy H:mm:ss'],
+ ['PreserveFormat', 'LastUsedFormat']
);
- $section->addField('PAGE', array('format' => 'ArabicDash'));
+ $section->addField('PAGE', ['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,
+ ]
);
$doc = TestHelperDOCX::getDocument($phpWord);
// TOC
$element = $doc->getElement('/w:document/w:body/w:p[1]/w:pPr/w:tabs/w:tab');
- $this->assertEquals('right', $element->getAttribute('w:val'));
- $this->assertEquals('dot', $element->getAttribute('w:leader'));
- $this->assertEquals(9062, $element->getAttribute('w:pos'));
+ self::assertEquals('right', $element->getAttribute('w:val'));
+ self::assertEquals('dot', $element->getAttribute('w:leader'));
+ self::assertEquals(9062, $element->getAttribute('w:pos'));
// Page break
$element = $doc->getElement('/w:document/w:body/w:p[4]/w:r/w:br');
- $this->assertEquals('page', $element->getAttribute('w:type'));
+ self::assertEquals('page', $element->getAttribute('w:type'));
// Title
$element = $doc->getElement('/w:document/w:body/w:p[6]/w:pPr/w:pStyle');
- $this->assertEquals('Heading1', $element->getAttribute('w:val'));
+ self::assertEquals('Heading1', $element->getAttribute('w:val'));
// List item
$element = $doc->getElement('/w:document/w:body/w:p[7]/w:pPr/w:numPr/w:numId');
- $this->assertEquals(3, $element->getAttribute('w:val'));
+ self::assertEquals(3, $element->getAttribute('w:val'));
// Object
$element = $doc->getElement('/w:document/w:body/w:p[12]/w:r/w:object/o:OLEObject');
- $this->assertEquals('Embed', $element->getAttribute('Type'));
+ self::assertEquals('Embed', $element->getAttribute('Type'));
}
/**
- * Write element with some styles
+ * Write element with some styles.
*/
- public function testElementStyles()
+ public function testElementStyles(): void
{
$objectSrc = __DIR__ . '/../../../_files/documents/sheet.xls';
- $tabs = array(new \PhpOffice\PhpWord\Style\Tab('right', 9090));
+ $tabs = [new \PhpOffice\PhpWord\Style\Tab('right', 9090)];
$phpWord = new PhpWord();
$phpWord->addParagraphStyle(
'pStyle',
- array(
- 'alignment' => Jc::CENTER,
- 'tabs' => $tabs,
- 'shading' => array('fill' => 'FFFF99'),
+ [
+ 'alignment' => Jc::CENTER,
+ 'tabs' => $tabs,
+ 'shading' => ['fill' => 'FFFF99'],
'borderSize' => 4,
- )
+ ]
); // Style #1
$phpWord->addFontStyle(
'fStyle',
- array(
- 'size' => '20',
- 'bold' => true,
+ [
+ 'size' => '20',
+ 'bold' => true,
'allCaps' => true,
- 'scale' => 200,
+ '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('alignment' => Jc::CENTER));
+ $phpWord->addTitleStyle(1, ['color' => '333333', 'doubleStrikethrough' => true]); // Style #3
+ $phpWord->addTableStyle('tStyle', ['borderSize' => 1]);
+ $fontStyle = new Font('text', ['alignment' => Jc::CENTER]);
$section = $phpWord->addSection();
$section->addListItem('List Item', 0, null, null, 'pStyle'); // Style #5
- $section->addObject($objectSrc, array('alignment' => Jc::CENTER));
+ $section->addObject($objectSrc, ['alignment' => Jc::CENTER]);
$section->addTOC($fontStyle);
$section->addTitle('Title 1', 1);
$section->addTOC('fStyle');
@@ -252,47 +252,47 @@ public function testElementStyles()
// List item
$element = $doc->getElement('/w:document/w:body/w:p[1]/w:pPr/w:numPr/w:numId');
- $this->assertEquals(5, $element->getAttribute('w:val'));
+ self::assertEquals(5, $element->getAttribute('w:val'));
// Object
$element = $doc->getElement('/w:document/w:body/w:p[2]/w:r/w:object/o:OLEObject');
- $this->assertEquals('Embed', $element->getAttribute('Type'));
+ self::assertEquals('Embed', $element->getAttribute('Type'));
// TOC
$element = $doc->getElement('/w:document/w:body/w:p[3]/w:pPr/w:tabs/w:tab');
- $this->assertEquals('right', $element->getAttribute('w:val'));
- $this->assertEquals('dot', $element->getAttribute('w:leader'));
- $this->assertEquals(9062, $element->getAttribute('w:pos'));
+ self::assertEquals('right', $element->getAttribute('w:val'));
+ self::assertEquals('dot', $element->getAttribute('w:leader'));
+ self::assertEquals(9062, $element->getAttribute('w:pos'));
}
/**
- * Test write text element
+ * Test write text element.
*/
- public function testWriteText()
+ public function testWriteText(): void
{
$rStyle = 'rStyle';
$pStyle = 'pStyle';
$phpWord = new PhpWord();
- $phpWord->addFontStyle($rStyle, array('bold' => true));
- $phpWord->addParagraphStyle($pStyle, array('hanging' => 120, 'indent' => 120));
+ $phpWord->addFontStyle($rStyle, ['bold' => true]);
+ $phpWord->addParagraphStyle($pStyle, ['hanging' => 120, 'indent' => 120]);
$section = $phpWord->addSection();
$section->addText('Test', $rStyle, $pStyle);
$doc = TestHelperDOCX::getDocument($phpWord);
$element = '/w:document/w:body/w:p/w:r/w:rPr/w:rStyle';
- $this->assertEquals($rStyle, $doc->getElementAttribute($element, 'w:val'));
+ self::assertEquals($rStyle, $doc->getElementAttribute($element, 'w:val'));
$element = '/w:document/w:body/w:p/w:pPr/w:pStyle';
- $this->assertEquals($pStyle, $doc->getElementAttribute($element, 'w:val'));
+ self::assertEquals($pStyle, $doc->getElementAttribute($element, 'w:val'));
}
/**
- * Test write textrun element
+ * Test write textrun element.
*/
- public function testWriteTextRun()
+ public function testWriteTextRun(): void
{
$pStyle = 'pStyle';
- $aStyle = array('alignment' => Jc::BOTH, 'spaceBefore' => 120, 'spaceAfter' => 120);
+ $aStyle = ['alignment' => Jc::BOTH, 'spaceBefore' => 120, 'spaceAfter' => 120];
$imageSrc = __DIR__ . '/../../../_files/images/earth.jpg';
$phpWord = new PhpWord();
@@ -303,24 +303,24 @@ public function testWriteTextRun()
$textrun->addTextBreak();
$textrun = $section->addTextRun($aStyle);
$textrun->addLink('https://github.com/PHPOffice/PHPWord');
- $textrun->addImage($imageSrc, array('alignment' => Jc::CENTER));
+ $textrun->addImage($imageSrc, ['alignment' => Jc::CENTER]);
$textrun->addFootnote();
$doc = TestHelperDOCX::getDocument($phpWord);
$parent = '/w:document/w:body/w:p';
- $this->assertTrue($doc->elementExists("{$parent}/w:pPr/w:pStyle[@w:val='{$pStyle}']"));
+ self::assertTrue($doc->elementExists("{$parent}/w:pPr/w:pStyle[@w:val='{$pStyle}']"));
}
/**
- * Test write link element
+ * Test write link element.
*/
- public function testWriteLink()
+ public function testWriteLink(): void
{
$phpWord = new PhpWord();
$section = $phpWord->addSection();
- $fontStyleArray = array('bold' => true);
+ $fontStyleArray = ['bold' => true];
$fontStyleName = 'Font Style';
- $paragraphStyleArray = array('alignment' => Jc::CENTER);
+ $paragraphStyleArray = ['alignment' => Jc::CENTER];
$paragraphStyleName = 'Paragraph Style';
$expected = 'PHPWord on GitHub';
@@ -331,20 +331,20 @@ public function testWriteLink()
$doc = TestHelperDOCX::getDocument($phpWord);
$element = $doc->getElement('/w:document/w:body/w:p/w:hyperlink/w:r/w:t');
- $this->assertEquals($expected, $element->nodeValue);
+ self::assertEquals($expected, $element->nodeValue);
}
/**
- * Test write preserve text element
+ * Test write preserve text element.
*/
- public function testWritePreserveText()
+ public function testWritePreserveText(): void
{
$phpWord = new PhpWord();
$section = $phpWord->addSection();
$footer = $section->addFooter();
- $fontStyleArray = array('bold' => true);
+ $fontStyleArray = ['bold' => true];
$fontStyleName = 'Font';
- $paragraphStyleArray = array('alignment' => Jc::END);
+ $paragraphStyleArray = ['alignment' => Jc::END];
$paragraphStyleName = 'Paragraph';
$footer->addPreserveText('Page {PAGE}');
@@ -354,17 +354,17 @@ public function testWritePreserveText()
$doc = TestHelperDOCX::getDocument($phpWord);
$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'));
+ self::assertEquals('PAGE', $preserve->nodeValue);
+ self::assertEquals('preserve', $preserve->getAttribute('xml:space'));
}
/**
- * Test write text break
+ * Test write text break.
*/
- public function testWriteTextBreak()
+ public function testWriteTextBreak(): void
{
- $fArray = array('size' => 12);
- $pArray = array('spacing' => 240);
+ $fArray = ['size' => 12];
+ $pArray = ['spacing' => 240];
$fName = 'fStyle';
$pName = 'pStyle';
@@ -378,19 +378,19 @@ public function testWriteTextBreak()
$doc = TestHelperDOCX::getDocument($phpWord);
$element = $doc->getElement('/w:document/w:body/w:p/w:pPr/w:rPr/w:rStyle');
- $this->assertEquals($fName, $element->getAttribute('w:val'));
+ self::assertEquals($fName, $element->getAttribute('w:val'));
$element = $doc->getElement('/w:document/w:body/w:p/w:pPr/w:pStyle');
- $this->assertEquals($pName, $element->getAttribute('w:val'));
+ self::assertEquals($pName, $element->getAttribute('w:val'));
}
/**
- * covers ::_writeImage
+ * covers ::_writeImage.
*/
- public function testWriteImage()
+ public function testWriteImage(): void
{
$phpWord = new PhpWord();
- $styles = array('alignment' => Jc::START, 'width' => 40, 'height' => 40, 'marginTop' => -1, 'marginLeft' => -1);
- $wraps = array('inline', 'behind', 'infront', 'square', 'tight');
+ $styles = ['alignment' => Jc::START, 'width' => 40, 'height' => 40, 'marginTop' => -1, 'marginLeft' => -1];
+ $wraps = ['inline', 'behind', 'infront', 'square', 'tight'];
$section = $phpWord->addSection();
foreach ($wraps as $wrap) {
$styles['wrappingStyle'] = $wrap;
@@ -407,17 +407,24 @@ 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);
+ // @phpstan-ignore-next-line
+ if (method_exists(self::class, 'assertMatchesRegularExpression')) {
+ self::assertMatchesRegularExpression('/z\-index:\-[0-9]*/', $style);
+ } elseif (method_exists(self::class, 'assertRegExp')) { // @phpstan-ignore-line
+ self::assertRegExp('/z\-index:\-[0-9]*/', $style);
+ } else {
+ self::fail('Unsure how to test regexp');
+ }
// square
$element = $doc->getElement('/w:document/w:body/w:p[4]/w:r/w:pict/v:shape/w10:wrap');
- $this->assertEquals('square', $element->getAttribute('type'));
+ self::assertEquals('square', $element->getAttribute('type'));
}
/**
- * covers ::_writeWatermark
+ * covers ::_writeWatermark.
*/
- public function testWriteWatermark()
+ public function testWriteWatermark(): void
{
$imageSrc = __DIR__ . '/../../../_files/images/earth.jpg';
@@ -428,27 +435,27 @@ public function testWriteWatermark()
$doc = TestHelperDOCX::getDocument($phpWord);
$element = $doc->getElement('/w:document/w:body/w:sectPr/w:headerReference');
- $this->assertStringStartsWith('rId', $element->getAttribute('r:id'));
+ self::assertStringStartsWith('rId', $element->getAttribute('r:id'));
}
/**
- * covers ::_writeTitle
+ * covers ::_writeTitle.
*/
- public function testWriteTitle()
+ public function testWriteTitle(): void
{
$phpWord = new PhpWord();
- $phpWord->addTitleStyle(1, array('bold' => true), array('spaceAfter' => 240));
+ $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';
- $this->assertEquals('Heading1', $doc->getElementAttribute($element, 'w:val'));
+ self::assertEquals('Heading1', $doc->getElementAttribute($element, 'w:val'));
}
/**
- * covers ::_writeCheckbox
+ * covers ::_writeCheckbox.
*/
- public function testWriteCheckbox()
+ public function testWriteCheckbox(): void
{
$rStyle = 'rStyle';
$pStyle = 'pStyle';
@@ -461,26 +468,26 @@ public function testWriteCheckbox()
$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'));
+ self::assertEquals('Check1', $doc->getElementAttribute($element, 'w:val'));
}
/**
- * covers ::_writeParagraphStyle
+ * covers ::_writeParagraphStyle.
*/
- public function testWriteParagraphStyle()
+ public function testWriteParagraphStyle(): void
{
// Create the doc
$phpWord = new PhpWord();
$section = $phpWord->addSection();
- $attributes = array(
- 'alignment' => Jc::END,
- 'widowControl' => false,
- 'keepNext' => true,
- 'keepLines' => true,
+ $attributes = [
+ 'alignment' => Jc::END,
+ 'widowControl' => false,
+ 'keepNext' => true,
+ 'keepLines' => true,
'pageBreakBefore' => true,
- );
+ ];
foreach ($attributes as $attribute => $value) {
- $section->addText('Test', null, array($attribute => $value));
+ $section->addText('Test', null, [$attribute => $value]);
}
$doc = TestHelperDOCX::getDocument($phpWord);
@@ -494,14 +501,14 @@ public function testWriteParagraphStyle()
$value = $value ? 1 : 0;
}
$element = $doc->getElement($path);
- $this->assertEquals($value, $element->getAttribute('w:val'));
+ self::assertEquals($value, $element->getAttribute('w:val'));
}
}
/**
- * covers ::_writeTextStyle
+ * covers ::_writeTextStyle.
*/
- public function testWriteFontStyle()
+ public function testWriteFontStyle(): void
{
$phpWord = new PhpWord();
$styles['name'] = 'Verdana';
@@ -522,22 +529,57 @@ public function testWriteFontStyle()
$doc = TestHelperDOCX::getDocument($phpWord);
$parent = '/w:document/w:body/w:p/w:r/w:rPr';
- $this->assertEquals($styles['name'], $doc->getElementAttribute("{$parent}/w:rFonts", 'w:ascii'));
- $this->assertEquals($styles['size'] * 2, $doc->getElementAttribute("{$parent}/w:sz", 'w:val'));
- $this->assertTrue($doc->elementExists("{$parent}/w:b"));
- $this->assertTrue($doc->elementExists("{$parent}/w:i"));
- $this->assertEquals($styles['underline'], $doc->getElementAttribute("{$parent}/w:u", 'w:val'));
- $this->assertTrue($doc->elementExists("{$parent}/w:strike"));
- $this->assertEquals('superscript', $doc->getElementAttribute("{$parent}/w:vertAlign", 'w:val'));
- $this->assertEquals($styles['color'], $doc->getElementAttribute("{$parent}/w:color", 'w:val'));
- $this->assertEquals($styles['fgColor'], $doc->getElementAttribute("{$parent}/w:highlight", 'w:val'));
- $this->assertTrue($doc->elementExists("{$parent}/w:smallCaps"));
+ self::assertEquals($styles['name'], $doc->getElementAttribute("{$parent}/w:rFonts", 'w:ascii'));
+ self::assertEquals($styles['size'] * 2, $doc->getElementAttribute("{$parent}/w:sz", 'w:val'));
+ self::assertTrue($doc->elementExists("{$parent}/w:b"));
+ 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
+ * Tests that if no color is set on a cell a border gets writen with the default color.
*/
- public function testWriteDefaultColor()
+ public function testWriteDefaultColor(): void
{
$phpWord = new PhpWord();
$section = $phpWord->addSection();
@@ -550,13 +592,19 @@ public function testWriteDefaultColor()
$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'));
+ 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'
+ )
+ );
}
/**
- * covers ::_writeTableStyle
+ * covers ::_writeTableStyle.
*/
- public function testWriteTableStyle()
+ public function testWriteTableStyle(): void
{
$phpWord = new PhpWord();
$rHeight = 120;
@@ -603,20 +651,20 @@ public function testWriteTableStyle()
$parent = '/w:document/w:body/w:tbl/w:tblPr/w:tblCellMar';
$parent = '/w:document/w:body/w:tbl/w:tr/w:trPr';
- $this->assertEquals($rHeight, $doc->getElementAttribute("{$parent}/w:trHeight", 'w:val'));
- $this->assertEquals($rStyles['tblHeader'], $doc->getElementAttribute("{$parent}/w:tblHeader", 'w:val'));
- $this->assertEquals($rStyles['cantSplit'], $doc->getElementAttribute("{$parent}/w:cantSplit", 'w:val'));
+ self::assertEquals($rHeight, $doc->getElementAttribute("{$parent}/w:trHeight", 'w:val'));
+ self::assertEquals($rStyles['tblHeader'], $doc->getElementAttribute("{$parent}/w:tblHeader", 'w:val'));
+ self::assertEquals($rStyles['cantSplit'], $doc->getElementAttribute("{$parent}/w:cantSplit", 'w:val'));
$parent = '/w:document/w:body/w:tbl/w:tr/w:tc/w:tcPr';
- $this->assertEquals($cWidth, $doc->getElementAttribute("{$parent}/w:tcW", 'w:w'));
- $this->assertEquals($cStyles['valign'], $doc->getElementAttribute("{$parent}/w:vAlign", 'w:val'));
- $this->assertEquals($cStyles['textDirection'], $doc->getElementAttribute("{$parent}/w:textDirection", 'w:val'));
+ self::assertEquals($cWidth, $doc->getElementAttribute("{$parent}/w:tcW", 'w:w'));
+ self::assertEquals($cStyles['valign'], $doc->getElementAttribute("{$parent}/w:vAlign", 'w:val'));
+ self::assertEquals($cStyles['textDirection'], $doc->getElementAttribute("{$parent}/w:textDirection", 'w:val'));
}
/**
- * covers ::_writeCellStyle
+ * covers ::_writeCellStyle.
*/
- public function testWriteCellStyleCellGridSpan()
+ public function testWriteCellStyleCellGridSpan(): void
{
$phpWord = new PhpWord();
$section = $phpWord->addSection();
@@ -635,28 +683,28 @@ public function testWriteCellStyleCellGridSpan()
$table->addCell(40);
$table->addRow();
- $cell = $table->addCell(200, array('borderRightColor' => 'FF0000'));
+ $cell = $table->addCell(200, ['borderRightColor' => 'FF0000']);
$cell->getStyle()->setGridSpan(5);
$doc = TestHelperDOCX::getDocument($phpWord);
$element = $doc->getElement('/w:document/w:body/w:tbl/w:tr/w:tc/w:tcPr/w:gridSpan');
- $this->assertEquals(5, $element->getAttribute('w:val'));
+ self::assertEquals(5, $element->getAttribute('w:val'));
}
/**
- * Test write gutter and line numbering
+ * Test write gutter and line numbering.
*/
- public function testWriteGutterAndLineNumbering()
+ public function testWriteGutterAndLineNumbering(): void
{
$pageMarginPath = '/w:document/w:body/w:sectPr/w:pgMar';
$lineNumberingPath = '/w:document/w:body/w:sectPr/w:lnNumType';
$phpWord = new PhpWord();
- $phpWord->addSection(array('gutter' => 240, 'lineNumbering' => array()));
+ $phpWord->addSection(['gutter' => 240, 'lineNumbering' => []]);
$doc = TestHelperDOCX::getDocument($phpWord);
- $this->assertEquals(240, $doc->getElement($pageMarginPath)->getAttribute('w:gutter'));
- $this->assertTrue($doc->elementExists($lineNumberingPath));
+ self::assertEquals(240, $doc->getElement($pageMarginPath)->getAttribute('w:gutter'));
+ self::assertTrue($doc->elementExists($lineNumberingPath));
}
}
diff --git a/tests/PhpWord/Writer/Word2007/Part/FooterTest.php b/tests/PhpWordTests/Writer/Word2007/Part/FooterTest.php
similarity index 68%
rename from tests/PhpWord/Writer/Word2007/Part/FooterTest.php
rename to tests/PhpWordTests/Writer/Word2007/Part/FooterTest.php
index 1f9bba0dd0..beb6e971e2 100644
--- a/tests/PhpWord/Writer/Word2007/Part/FooterTest.php
+++ b/tests/PhpWordTests/Writer/Word2007/Part/FooterTest.php
@@ -1,4 +1,5 @@
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());
- $this->assertInstanceOf('SimpleXMLElement', $xml);
+ self::assertInstanceOf('SimpleXMLElement', $xml);
+ TestHelperDOCX::deleteDir($dir);
}
}
diff --git a/tests/PhpWord/Writer/Word2007/Part/FootnotesTest.php b/tests/PhpWordTests/Writer/Word2007/Part/FootnotesTest.php
similarity index 63%
rename from tests/PhpWord/Writer/Word2007/Part/FootnotesTest.php
rename to tests/PhpWordTests/Writer/Word2007/Part/FootnotesTest.php
index 4b0e94df30..d8bf678541 100644
--- a/tests/PhpWord/Writer/Word2007/Part/FootnotesTest.php
+++ b/tests/PhpWordTests/Writer/Word2007/Part/FootnotesTest.php
@@ -1,4 +1,5 @@
addParagraphStyle('pStyle', array('alignment' => Jc::START));
+ $phpWord->addParagraphStyle('pStyle', ['alignment' => Jc::START]);
$section = $phpWord->addSection();
$section->addText('Text');
$footnote1 = $section->addFootnote('pStyle');
$footnote1->addText('Footnote');
$footnote1->addTextBreak();
$footnote1->addLink('https://github.com/PHPOffice/PHPWord');
- $footnote2 = $section->addEndnote(array('alignment' => Jc::START));
+ $footnote2 = $section->addEndnote(['alignment' => Jc::START]);
$footnote2->addText('Endnote');
$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'));
+ 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"]'));
}
}
diff --git a/tests/PhpWord/Writer/Word2007/Part/HeaderTest.php b/tests/PhpWordTests/Writer/Word2007/Part/HeaderTest.php
similarity index 68%
rename from tests/PhpWord/Writer/Word2007/Part/HeaderTest.php
rename to tests/PhpWordTests/Writer/Word2007/Part/HeaderTest.php
index 9edd0063bd..164365f113 100644
--- a/tests/PhpWord/Writer/Word2007/Part/HeaderTest.php
+++ b/tests/PhpWordTests/Writer/Word2007/Part/HeaderTest.php
@@ -1,4 +1,5 @@
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());
- $this->assertInstanceOf('SimpleXMLElement', $xml);
+ self::assertInstanceOf('SimpleXMLElement', $xml);
+ TestHelperDOCX::deleteDir($dir);
}
}
diff --git a/tests/PhpWord/Writer/Word2007/Part/NumberingTest.php b/tests/PhpWordTests/Writer/Word2007/Part/NumberingTest.php
similarity index 57%
rename from tests/PhpWord/Writer/Word2007/Part/NumberingTest.php
rename to tests/PhpWordTests/Writer/Word2007/Part/NumberingTest.php
index fb5a220e88..1cf596fc85 100644
--- a/tests/PhpWord/Writer/Word2007/Part/NumberingTest.php
+++ b/tests/PhpWordTests/Writer/Word2007/Part/NumberingTest.php
@@ -1,4 +1,5 @@
addNumberingStyle(
'numStyle',
- array(
- 'type' => 'multilevel',
- 'levels' => array(
- array(
- 'start' => 1,
- 'format' => NumberFormat::DECIMAL,
- 'restart' => 1,
- 'suffix' => 'space',
- 'text' => '%1.',
+ [
+ 'type' => 'multilevel',
+ 'levels' => [
+ [
+ 'start' => 1,
+ 'format' => NumberFormat::DECIMAL,
+ 'restart' => 1,
+ 'suffix' => 'space',
+ 'text' => '%1.',
'alignment' => Jc::START,
- 'left' => 360,
- 'hanging' => 360,
- 'tabPos' => 360,
- 'font' => 'Arial',
- 'hint' => 'default',
- ),
- ),
- )
+ 'left' => 360,
+ 'hanging' => 360,
+ 'tabPos' => 360,
+ 'font' => 'Arial',
+ 'hint' => 'default',
+ ],
+ ],
+ ]
);
$doc = TestHelperDOCX::getDocument($phpWord, 'Word2007');
- $this->assertTrue($doc->elementExists('/w:numbering/w:abstractNum', $xmlFile));
+ self::assertTrue($doc->elementExists('/w:numbering/w:abstractNum', $xmlFile));
}
}
diff --git a/tests/PhpWord/Writer/Word2007/Part/SettingsTest.php b/tests/PhpWordTests/Writer/Word2007/Part/SettingsTest.php
similarity index 55%
rename from tests/PhpWord/Writer/Word2007/Part/SettingsTest.php
rename to tests/PhpWordTests/Writer/Word2007/Part/SettingsTest.php
index 8a21e827cd..107b94b1be 100644
--- a/tests/PhpWord/Writer/Word2007/Part/SettingsTest.php
+++ b/tests/PhpWordTests/Writer/Word2007/Part/SettingsTest.php
@@ -1,4 +1,5 @@
getSettings()->getDocumentProtection()->setEditing('forms');
@@ -53,13 +54,13 @@ public function testDocumentProtection()
$file = 'word/settings.xml';
$path = '/w:settings/w:documentProtection';
- $this->assertTrue($doc->elementExists($path, $file));
+ self::assertTrue($doc->elementExists($path, $file));
}
/**
- * Test document protection with password
+ * Test document protection with password.
*/
- public function testDocumentProtectionWithPassword()
+ public function testDocumentProtectionWithPassword(): void
{
$phpWord = new PhpWord();
$phpWord->getSettings()->getDocumentProtection()->setEditing('readOnly');
@@ -67,22 +68,49 @@ 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);
$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'));
+ self::assertTrue($doc->elementExists($path, $file));
+ self::assertEquals('rUuJbk6LuN2/qFyp7IUPQA==', $doc->getElement($path, $file)->getAttribute('w:hash'));
+ self::assertEquals('1', $doc->getElement($path, $file)->getAttribute('w:cryptAlgorithmSid'));
+ self::assertEquals('10', $doc->getElement($path, $file)->getAttribute('w:cryptSpinCount'));
}
/**
- * Test compatibility
+ * Test document protection with password without setting salt.
*/
- public function testCompatibility()
+ public function testDocumentProtectionWithPasswordNoSalt(): void
+ {
+ $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';
+ self::assertTrue($doc->elementExists($path, $file));
+ //$this->assertEquals('rUuJbk6LuN2/qFyp7IUPQA==', $doc->getElement($path, $file)->getAttribute('w:hash'));
+ self::assertEquals('1', $doc->getElement($path, $file)->getAttribute('w:cryptAlgorithmSid'));
+ self::assertEquals('10', $doc->getElement($path, $file)->getAttribute('w:cryptSpinCount'));
+ }
+
+ /**
+ * Test compatibility.
+ */
+ public function testCompatibility(): void
{
$phpWord = new PhpWord();
$phpWord->getCompatibility()->setOoxmlVersion(15);
@@ -92,14 +120,14 @@ public function testCompatibility()
$file = 'word/settings.xml';
$path = '/w:settings/w:compat/w:compatSetting';
- $this->assertTrue($doc->elementExists($path, $file));
- $this->assertEquals($phpWord->getCompatibility()->getOoxmlVersion(), 15);
+ self::assertTrue($doc->elementExists($path, $file));
+ self::assertEquals($phpWord->getCompatibility()->getOoxmlVersion(), 15);
}
/**
- * Test language
+ * Test language.
*/
- public function testDefaultLanguage()
+ public function testDefaultLanguage(): void
{
$phpWord = new PhpWord();
@@ -108,16 +136,16 @@ public function testDefaultLanguage()
$file = 'word/settings.xml';
$path = '/w:settings/w:themeFontLang';
- $this->assertTrue($doc->elementExists($path, $file));
+ self::assertTrue($doc->elementExists($path, $file));
$element = $doc->getElement($path, $file);
- $this->assertEquals('en-US', $element->getAttribute('w:val'));
+ self::assertEquals('en-US', $element->getAttribute('w:val'));
}
/**
- * Test language
+ * Test language.
*/
- public function testLanguage()
+ public function testLanguage(): void
{
$phpWord = new PhpWord();
$phpWord->getSettings()->setThemeFontLang(new Language(Language::DE_DE, Language::KO_KR, Language::HE_IL));
@@ -126,18 +154,18 @@ public function testLanguage()
$file = 'word/settings.xml';
$path = '/w:settings/w:themeFontLang';
- $this->assertTrue($doc->elementExists($path, $file));
+ self::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'));
+ self::assertEquals(Language::DE_DE, $element->getAttribute('w:val'));
+ self::assertEquals(Language::KO_KR, $element->getAttribute('w:eastAsia'));
+ self::assertEquals(Language::HE_IL, $element->getAttribute('w:bidi'));
}
/**
- * Test proofState
+ * Test proofState.
*/
- public function testProofState()
+ public function testProofState(): void
{
$proofState = new ProofState();
$proofState->setSpelling(ProofState::DIRTY);
@@ -150,17 +178,17 @@ public function testProofState()
$file = 'word/settings.xml';
$path = '/w:settings/w:proofState';
- $this->assertTrue($doc->elementExists($path, $file));
+ self::assertTrue($doc->elementExists($path, $file));
$element = $doc->getElement($path, $file);
- $this->assertEquals('dirty', $element->getAttribute('w:spelling'));
- $this->assertEquals('dirty', $element->getAttribute('w:grammar'));
+ self::assertEquals('dirty', $element->getAttribute('w:spelling'));
+ self::assertEquals('dirty', $element->getAttribute('w:grammar'));
}
/**
- * Test spelling
+ * Test spelling.
*/
- public function testSpelling()
+ public function testSpelling(): void
{
$phpWord = new PhpWord();
$phpWord->getSettings()->setHideSpellingErrors(true);
@@ -170,16 +198,16 @@ public function testSpelling()
$file = 'word/settings.xml';
$path = '/w:settings/w:hideSpellingErrors';
- $this->assertTrue($doc->elementExists($path, $file));
+ self::assertTrue($doc->elementExists($path, $file));
$element = $doc->getElement($path, $file);
- $this->assertSame('true', $element->getAttribute('w:val'));
+ self::assertSame('true', $element->getAttribute('w:val'));
}
/**
- * Test even and odd headers
+ * Test even and odd headers.
*/
- public function testEvenAndOddHeaders()
+ public function testEvenAndOddHeaders(): void
{
$phpWord = new PhpWord();
$phpWord->getSettings()->setEvenAndOddHeaders(true);
@@ -189,13 +217,13 @@ public function testEvenAndOddHeaders()
$file = 'word/settings.xml';
$path = '/w:settings/w:evenAndOddHeaders';
- $this->assertTrue($doc->elementExists($path, $file));
+ self::assertTrue($doc->elementExists($path, $file));
$element = $doc->getElement($path, $file);
- $this->assertSame('true', $element->getAttribute('w:val'));
+ self::assertSame('true', $element->getAttribute('w:val'));
}
- public function testUpdateFields()
+ public function testUpdateFields(): void
{
$phpWord = new PhpWord();
$phpWord->getSettings()->setUpdateFields(true);
@@ -205,16 +233,16 @@ public function testUpdateFields()
$file = 'word/settings.xml';
$path = '/w:settings/w:updateFields';
- $this->assertTrue($doc->elementExists($path, $file));
+ self::assertTrue($doc->elementExists($path, $file));
$element = $doc->getElement($path, $file);
- $this->assertSame('true', $element->getAttribute('w:val'));
+ self::assertSame('true', $element->getAttribute('w:val'));
}
/**
- * Test zoom percentage
+ * Test zoom percentage.
*/
- public function testZoomPercentage()
+ public function testZoomPercentage(): void
{
$phpWord = new PhpWord();
$phpWord->getSettings()->setZoom(75);
@@ -224,16 +252,16 @@ public function testZoomPercentage()
$file = 'word/settings.xml';
$path = '/w:settings/w:zoom';
- $this->assertTrue($doc->elementExists($path, $file));
+ self::assertTrue($doc->elementExists($path, $file));
$element = $doc->getElement($path, $file);
- $this->assertEquals('75', $element->getAttribute('w:percent'));
+ self::assertEquals('75', $element->getAttribute('w:percent'));
}
/**
- * Test zoom value
+ * Test zoom value.
*/
- public function testZoomValue()
+ public function testZoomValue(): void
{
$phpWord = new PhpWord();
$phpWord->getSettings()->setZoom(Zoom::FULL_PAGE);
@@ -243,13 +271,13 @@ public function testZoomValue()
$file = 'word/settings.xml';
$path = '/w:settings/w:zoom';
- $this->assertTrue($doc->elementExists($path, $file));
+ self::assertTrue($doc->elementExists($path, $file));
$element = $doc->getElement($path, $file);
- $this->assertEquals('fullPage', $element->getAttribute('w:val'));
+ self::assertEquals('fullPage', $element->getAttribute('w:val'));
}
- public function testMirrorMargins()
+ public function testMirrorMargins(): void
{
$phpWord = new PhpWord();
$phpWord->getSettings()->setMirrorMargins(true);
@@ -259,16 +287,16 @@ public function testMirrorMargins()
$file = 'word/settings.xml';
$path = '/w:settings/w:mirrorMargins';
- $this->assertTrue($doc->elementExists($path, $file));
+ self::assertTrue($doc->elementExists($path, $file));
$element = $doc->getElement($path, $file);
- $this->assertSame('true', $element->getAttribute('w:val'));
+ self::assertSame('true', $element->getAttribute('w:val'));
}
/**
- * Test Revision View
+ * Test Revision View.
*/
- public function testRevisionView()
+ public function testRevisionView(): void
{
$trackChangesView = new TrackChangesView();
$trackChangesView->setFormatting(false);
@@ -282,14 +310,14 @@ public function testRevisionView()
$file = 'word/settings.xml';
$path = '/w:settings/w:revisionView';
- $this->assertTrue($doc->elementExists($path, $file));
+ self::assertTrue($doc->elementExists($path, $file));
$element = $doc->getElement($path, $file);
- $this->assertEquals('false', $element->getAttribute('w:formatting'));
- $this->assertEquals('true', $element->getAttribute('w:comments'));
+ self::assertEquals('false', $element->getAttribute('w:formatting'));
+ self::assertEquals('true', $element->getAttribute('w:comments'));
}
- public function testHideSpellingErrors()
+ public function testHideSpellingErrors(): void
{
$phpWord = new PhpWord();
$phpWord->getSettings()->setHideSpellingErrors(true);
@@ -299,13 +327,13 @@ public function testHideSpellingErrors()
$file = 'word/settings.xml';
$path = '/w:settings/w:hideSpellingErrors';
- $this->assertTrue($doc->elementExists($path, $file));
+ self::assertTrue($doc->elementExists($path, $file));
$element = $doc->getElement($path, $file);
- $this->assertSame('true', $element->getAttribute('w:val'));
+ self::assertSame('true', $element->getAttribute('w:val'));
}
- public function testHideGrammaticalErrors()
+ public function testHideGrammaticalErrors(): void
{
$phpWord = new PhpWord();
$phpWord->getSettings()->setHideGrammaticalErrors(true);
@@ -315,16 +343,16 @@ public function testHideGrammaticalErrors()
$file = 'word/settings.xml';
$path = '/w:settings/w:hideGrammaticalErrors';
- $this->assertTrue($doc->elementExists($path, $file));
+ self::assertTrue($doc->elementExists($path, $file));
$element = $doc->getElement($path, $file);
- $this->assertSame('true', $element->getAttribute('w:val'));
+ self::assertSame('true', $element->getAttribute('w:val'));
}
/**
- * Test track Revisions
+ * Test track Revisions.
*/
- public function testTrackRevisions()
+ public function testTrackRevisions(): void
{
$phpWord = new PhpWord();
$phpWord->getSettings()->setTrackRevisions(true);
@@ -334,16 +362,16 @@ public function testTrackRevisions()
$file = 'word/settings.xml';
$path = '/w:settings/w:trackRevisions';
- $this->assertTrue($doc->elementExists($path, $file));
+ self::assertTrue($doc->elementExists($path, $file));
$element = $doc->getElement($path, $file);
- $this->assertSame('true', $element->getAttribute('w:val'));
+ self::assertSame('true', $element->getAttribute('w:val'));
}
/**
- * Test doNotTrackMoves
+ * Test doNotTrackMoves.
*/
- public function testDoNotTrackMoves()
+ public function testDoNotTrackMoves(): void
{
$phpWord = new PhpWord();
$phpWord->getSettings()->setDoNotTrackMoves(true);
@@ -353,16 +381,16 @@ public function testDoNotTrackMoves()
$file = 'word/settings.xml';
$path = '/w:settings/w:doNotTrackMoves';
- $this->assertTrue($doc->elementExists($path, $file));
+ self::assertTrue($doc->elementExists($path, $file));
$element = $doc->getElement($path, $file);
- $this->assertSame('true', $element->getAttribute('w:val'));
+ self::assertSame('true', $element->getAttribute('w:val'));
}
/**
- * Test DoNotTrackFormatting
+ * Test DoNotTrackFormatting.
*/
- public function testDoNotTrackFormatting()
+ public function testDoNotTrackFormatting(): void
{
$phpWord = new PhpWord();
$phpWord->getSettings()->setDoNotTrackFormatting(true);
@@ -372,13 +400,13 @@ public function testDoNotTrackFormatting()
$file = 'word/settings.xml';
$path = '/w:settings/w:doNotTrackFormatting';
- $this->assertTrue($doc->elementExists($path, $file));
+ self::assertTrue($doc->elementExists($path, $file));
$element = $doc->getElement($path, $file);
- $this->assertSame('true', $element->getAttribute('w:val'));
+ self::assertSame('true', $element->getAttribute('w:val'));
}
- public function testAutoHyphenation()
+ public function testAutoHyphenation(): void
{
$phpWord = new PhpWord();
$phpWord->getSettings()->setAutoHyphenation(true);
@@ -388,13 +416,13 @@ public function testAutoHyphenation()
$file = 'word/settings.xml';
$path = '/w:settings/w:autoHyphenation';
- $this->assertTrue($doc->elementExists($path, $file));
+ self::assertTrue($doc->elementExists($path, $file));
$element = $doc->getElement($path, $file);
- $this->assertSame('true', $element->getAttribute('w:val'));
+ self::assertSame('true', $element->getAttribute('w:val'));
}
- public function testConsecutiveHyphenLimit()
+ public function testConsecutiveHyphenLimit(): void
{
$phpWord = new PhpWord();
$phpWord->getSettings()->setConsecutiveHyphenLimit(2);
@@ -404,13 +432,13 @@ public function testConsecutiveHyphenLimit()
$file = 'word/settings.xml';
$path = '/w:settings/w:consecutiveHyphenLimit';
- $this->assertTrue($doc->elementExists($path, $file));
+ self::assertTrue($doc->elementExists($path, $file));
$element = $doc->getElement($path, $file);
- $this->assertSame('2', $element->getAttribute('w:val'));
+ self::assertSame('2', $element->getAttribute('w:val'));
}
- public function testHyphenationZone()
+ public function testHyphenationZone(): void
{
$phpWord = new PhpWord();
$phpWord->getSettings()->setHyphenationZone(100);
@@ -420,13 +448,13 @@ public function testHyphenationZone()
$file = 'word/settings.xml';
$path = '/w:settings/w:hyphenationZone';
- $this->assertTrue($doc->elementExists($path, $file));
+ self::assertTrue($doc->elementExists($path, $file));
$element = $doc->getElement($path, $file);
- $this->assertSame('100', $element->getAttribute('w:val'));
+ self::assertSame('100', $element->getAttribute('w:val'));
}
- public function testDoNotHyphenateCaps()
+ public function testDoNotHyphenateCaps(): void
{
$phpWord = new PhpWord();
$phpWord->getSettings()->setDoNotHyphenateCaps(true);
@@ -436,9 +464,25 @@ public function testDoNotHyphenateCaps()
$file = 'word/settings.xml';
$path = '/w:settings/w:doNotHyphenateCaps';
- $this->assertTrue($doc->elementExists($path, $file));
+ self::assertTrue($doc->elementExists($path, $file));
+
+ $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);
- $this->assertSame('true', $element->getAttribute('w:val'));
+ self::assertSame('true', $element->getAttribute('w:val'));
}
}
diff --git a/tests/PhpWord/Writer/Word2007/Part/StylesTest.php b/tests/PhpWordTests/Writer/Word2007/Part/StylesTest.php
similarity index 64%
rename from tests/PhpWord/Writer/Word2007/Part/StylesTest.php
rename to tests/PhpWordTests/Writer/Word2007/Part/StylesTest.php
index 91f371841d..09936d6d33 100644
--- a/tests/PhpWord/Writer/Word2007/Part/StylesTest.php
+++ b/tests/PhpWordTests/Writer/Word2007/Part/StylesTest.php
@@ -1,4 +1,5 @@
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');
+ $pStyle = ['alignment' => Jc::BOTH];
+ $pBase = ['basedOn' => 'Normal'];
+ $pNew = ['basedOn' => 'Base Style', 'next' => 'Normal'];
+ $rStyle = ['size' => 20];
+ $tStyle = ['bgColor' => 'FF0000', 'cellMargin' => 120, 'borderSize' => 120];
+ $firstRowStyle = ['bgColor' => '0000FF', 'borderSize' => 120, 'borderColor' => '00FF00'];
$phpWord->setDefaultParagraphStyle($pStyle);
$phpWord->addParagraphStyle('Base Style', $pBase);
$phpWord->addParagraphStyle('New Style', $pNew);
@@ -65,20 +67,20 @@ public function testWriteStyles()
// Normal style generated?
$path = '/w:styles/w:style[@w:styleId="Normal"]/w:name';
$element = $doc->getElement($path, $file);
- $this->assertEquals('Normal', $element->getAttribute('w:val'));
+ self::assertEquals('Normal', $element->getAttribute('w:val'));
// Parent style referenced?
$path = '/w:styles/w:style[@w:styleId="New Style"]/w:basedOn';
$element = $doc->getElement($path, $file);
- $this->assertEquals('Base Style', $element->getAttribute('w:val'));
+ self::assertEquals('Base Style', $element->getAttribute('w:val'));
// Next paragraph style correct?
$path = '/w:styles/w:style[@w:styleId="New Style"]/w:next';
$element = $doc->getElement($path, $file);
- $this->assertEquals('Normal', $element->getAttribute('w:val'));
+ self::assertEquals('Normal', $element->getAttribute('w:val'));
}
- public function testFontStyleBasedOn()
+ public function testFontStyleBasedOn(): void
{
$phpWord = new PhpWord();
@@ -102,20 +104,20 @@ public function testFontStyleBasedOn()
// 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'));
+ self::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'));
+ self::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);
+ self::assertNull($element);
}
- public function testFontStyleBasedOnOtherFontStyle()
+ public function testFontStyleBasedOnOtherFontStyle(): void
{
$phpWord = new PhpWord();
@@ -141,6 +143,44 @@ public function testFontStyleBasedOnOtherFontStyle()
$path = '/w:styles/w:style[@w:styleId="GeneratEteinte"]/w:basedOn';
$element = $doc->getElement($path, $file);
- $this->assertEquals('Generation', $element->getAttribute('w:val'));
+ 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'));
}
}
diff --git a/tests/PhpWord/Writer/Word2007/PartTest.php b/tests/PhpWordTests/Writer/Word2007/PartTest.php
similarity index 75%
rename from tests/PhpWord/Writer/Word2007/PartTest.php
rename to tests/PhpWordTests/Writer/Word2007/PartTest.php
index 277f61e1be..be69e587e3 100644
--- a/tests/PhpWord/Writer/Word2007/PartTest.php
+++ b/tests/PhpWordTests/Writer/Word2007/PartTest.php
@@ -1,4 +1,5 @@
expectException(\PhpOffice\PhpWord\Exception\Exception::class);
+ $this->expectExceptionMessage('Invalid parameters passed.');
$object = new RelsPart();
- $object->setMedia(array(array('type' => '', 'target' => '')));
+ $object->setMedia([['type' => '', 'target' => '']]);
$object->write();
}
}
diff --git a/tests/PhpWordTests/Writer/Word2007/Style/DirectionTest.php b/tests/PhpWordTests/Writer/Word2007/Style/DirectionTest.php
new file mode 100644
index 0000000000..efd855af23
--- /dev/null
+++ b/tests/PhpWordTests/Writer/Word2007/Style/DirectionTest.php
@@ -0,0 +1,62 @@
+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/Word2007/Style/FontTest.php b/tests/PhpWordTests/Writer/Word2007/Style/FontTest.php
new file mode 100644
index 0000000000..c0e2653a7c
--- /dev/null
+++ b/tests/PhpWordTests/Writer/Word2007/Style/FontTest.php
@@ -0,0 +1,201 @@
+addSection();
+ $textrun = $section->addTextRun();
+ $textrun->addText('سلام این یک پاراگراف راست به چپ است', ['rtl' => true, 'lang' => 'ar-DZ']);
+ $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007');
+
+ $file = 'word/document.xml';
+ $path = '/w:document/w:body/w:p/w:r/w:rPr/w:rtl';
+ self::assertTrue($doc->elementExists($path, $file));
+ }
+
+ public function testFontRTLNamed(): void
+ {
+ $phpWord = new PhpWord();
+ $stnam = 'fstyle';
+ $phpWord->addFontStyle($stnam, [
+ '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';
+ self::assertTrue($doc->elementExists($txtelem));
+ self::assertEquals($txt, $doc->getElement($txtelem)->textContent);
+ self::assertTrue($doc->elementExists($styelem));
+ self::assertTrue($doc->elementExists($styelem . '/w:rStyle'));
+ self::assertEquals($stnam, $doc->getElementAttribute($styelem . '/w:rStyle', 'w:val'));
+ self::assertTrue($doc->elementExists($styelem . '/w:rtl'));
+ }
+
+ public function testFontNotRTLNamed(): void
+ {
+ $phpWord = new PhpWord();
+ $stnam = 'fstyle';
+ $phpWord->addFontStyle($stnam, [
+ //'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';
+ self::assertTrue($doc->elementExists($txtelem));
+ self::assertEquals($txt, $doc->getElement($txtelem)->textContent);
+ self::assertTrue($doc->elementExists($styelem));
+ self::assertTrue($doc->elementExists($styelem . '/w:rStyle'));
+ self::assertEquals($stnam, $doc->getElementAttribute($styelem . '/w:rStyle', 'w:val'));
+ self::assertFalse($doc->elementExists($styelem . '/w:rtl'));
+ }
+
+ public function testNoProof(): void
+ {
+ $phpWord = new PhpWord();
+ $fontStyle = [
+ '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';
+ self::assertTrue($doc->elementExists($txtelem));
+ self::assertEquals($txt, $doc->getElement($txtelem)->textContent);
+ self::assertTrue($doc->elementExists($styelem));
+ self::assertTrue($doc->elementExists($noproofelem));
+ self::assertEquals('1', $doc->getElementAttribute($noproofelem, 'w:val'));
+ }
+
+ /**
+ * Test writing font with language.
+ */
+ public function testFontWithLang(): void
+ {
+ $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');
+
+ $file = 'word/document.xml';
+ $path = '/w:document/w:body/w:p/w:r/w:rPr/w:lang';
+ self::assertTrue($doc->elementExists($path, $file));
+ }
+
+ /**
+ * Test writing position.
+ */
+ public function testPosition(): void
+ {
+ $phpWord = new PhpWord();
+ $section = $phpWord->addSection();
+ $section->addText('This text is lowered', ['position' => -20]);
+ $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007');
+
+ $path = '/w:document/w:body/w:p/w:r/w:rPr/w:position';
+ self::assertTrue($doc->elementExists($path));
+ self::assertEquals(-20, $doc->getElementAttribute($path, 'w:val'));
+ }
+
+ public static function testRgb(): void
+ {
+ $phpWord = new PhpWord();
+ $section = $phpWord->addSection(['pageNumberingStart' => 1]);
+ $html = implode(
+ "\n",
+ [
+ '',
+ '',
+ '',
+ 'This one is in color. ',
+ 'This one too. ',
+ ' ',
+ ' ',
+ '
',
+ ]
+ );
+
+ Html::addHtml($section, $html, false, false);
+ $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007');
+
+ $element = '/w:document/w:body/w:tbl/w:tr/w:tc/w:p/w:r';
+ $txtelem = $element . '/w:t';
+ $styelem = $element . '/w:rPr';
+ self::assertTrue($doc->elementExists($txtelem));
+ self::assertSame('This one is in color.', $doc->getElement($txtelem)->textContent);
+ self::assertTrue($doc->elementExists($styelem));
+ self::assertTrue($doc->elementExists($styelem . '/w:color'));
+ self::assertSame('A7D9C1', $doc->getElementAttribute($styelem . '/w:color', 'w:val'));
+
+ $element = '/w:document/w:body/w:tbl/w:tr/w:tc[2]/w:p/w:r';
+ $txtelem = $element . '/w:t';
+ $styelem = $element . '/w:rPr';
+ self::assertTrue($doc->elementExists($txtelem));
+ self::assertSame('This one too.', $doc->getElement($txtelem)->textContent);
+ self::assertTrue($doc->elementExists($styelem));
+ self::assertTrue($doc->elementExists($styelem . '/w:color'));
+ self::assertSame('A7D9C1', $doc->getElementAttribute($styelem . '/w:color', 'w:val'));
+ }
+}
diff --git a/tests/PhpWordTests/Writer/Word2007/Style/ImageTest.php b/tests/PhpWordTests/Writer/Word2007/Style/ImageTest.php
new file mode 100644
index 0000000000..2b5c25e01f
--- /dev/null
+++ b/tests/PhpWordTests/Writer/Word2007/Style/ImageTest.php
@@ -0,0 +1,107 @@
+ 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:rPr/w:position';
+ self::assertFalse($doc->elementExists($path));
+ $path = '/w:document/w:body/w:p[1]/w:r/w:pict/v:shape';
+ self::assertTrue($doc->elementExists($path . '/w10:wrap'));
+ self::assertEquals('inline', $doc->getElementAttribute($path . '/w10:wrap', 'type'));
+
+ self::assertTrue($doc->elementExists($path));
+ $style = $doc->getElement($path)->getAttribute('style');
+ self::assertNotNull($style);
+ self::assertStringContainsString('mso-wrap-distance-left:10pt;', $style);
+ self::assertStringContainsString('mso-wrap-distance-right:20pt;', $style);
+ self::assertStringContainsString('mso-wrap-distance-top:30pt;', $style);
+ self::assertStringContainsString('mso-wrap-distance-bottom:40pt;', $style);
+ }
+
+ /**
+ * Test writing image wrapping.
+ */
+ public function testWrappingWithPosition(): void
+ {
+ $styles = [
+ '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';
+ self::assertEquals('10', $doc->getElement($path)->getAttribute('w:val'));
+ $path = '/w:document/w:body/w:p[1]/w:r/w:pict/v:shape';
+ self::assertTrue($doc->elementExists($path . '/w10:wrap'));
+ self::assertEquals('inline', $doc->getElementAttribute($path . '/w10:wrap', 'type'));
+
+ self::assertTrue($doc->elementExists($path));
+ $style = $doc->getElement($path)->getAttribute('style');
+ self::assertNotNull($style);
+ self::assertStringContainsString('mso-wrap-distance-left:10pt;', $style);
+ self::assertStringContainsString('mso-wrap-distance-right:20pt;', $style);
+ self::assertStringContainsString('mso-wrap-distance-top:30pt;', $style);
+ self::assertStringContainsString('mso-wrap-distance-bottom:40pt;', $style);
+ }
+}
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 @@
+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'));
+ }
+}
diff --git a/tests/PhpWord/Writer/Word2007/Style/ParagraphTest.php b/tests/PhpWordTests/Writer/Word2007/Style/ParagraphTest.php
similarity index 62%
rename from tests/PhpWord/Writer/Word2007/Style/ParagraphTest.php
rename to tests/PhpWordTests/Writer/Word2007/Style/ParagraphTest.php
index 843f98807f..c1f985ccd2 100644
--- a/tests/PhpWord/Writer/Word2007/Style/ParagraphTest.php
+++ b/tests/PhpWordTests/Writer/Word2007/Style/ParagraphTest.php
@@ -1,4 +1,5 @@
addParagraphStyle('testStyle', array('indent' => '10'));
+ $phpWord->addParagraphStyle('testStyle', ['indent' => '10']);
$section = $phpWord->addSection();
- $section->addText('test', null, array('numStyle' => 'testStyle', 'numLevel' => '1'));
+ $section->addText('test', null, ['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));
+ self::assertTrue($doc->elementExists($path));
}
- public function testLineSpacingExact()
+ public function testLineSpacingExact(): void
{
$phpWord = new \PhpOffice\PhpWord\PhpWord();
$section = $phpWord->addSection();
- $section->addText('test', null, array('spacing' => 240, 'spacingLineRule' => 'exact'));
+ $section->addText('test', null, ['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'));
+ self::assertTrue($doc->elementExists($path));
+ self::assertEquals('exact', $doc->getElementAttribute($path, 'w:lineRule'));
+ self::assertEquals('240', $doc->getElementAttribute($path, 'w:line'));
}
- public function testLineSpacingAuto()
+ public function testLineSpacingAuto(): void
{
$phpWord = new \PhpOffice\PhpWord\PhpWord();
$section = $phpWord->addSection();
- $section->addText('test', null, array('spacing' => 240, 'spacingLineRule' => 'auto'));
+ $section->addText('test', null, ['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'));
+ self::assertTrue($doc->elementExists($path));
+ self::assertEquals('auto', $doc->getElementAttribute($path, 'w:lineRule'));
+ self::assertEquals('480', $doc->getElementAttribute($path, 'w:line'));
}
- public function testSuppressAutoHyphens()
+ public function testSuppressAutoHyphens(): void
{
$paragraphStyle = new ParagraphStyle();
$paragraphStyle->setSuppressAutoHyphens(true);
@@ -88,6 +90,6 @@ public function testSuppressAutoHyphens()
$doc = TestHelperDOCX::getDocument($phpWord, 'Word2007');
$path = '/w:document/w:body/w:p/w:pPr/w:suppressAutoHyphens';
- $this->assertTrue($doc->elementExists($path));
+ self::assertTrue($doc->elementExists($path));
}
}
diff --git a/tests/PhpWordTests/Writer/Word2007/Style/SectionTest.php b/tests/PhpWordTests/Writer/Word2007/Style/SectionTest.php
new file mode 100644
index 0000000000..f527ded190
--- /dev/null
+++ b/tests/PhpWordTests/Writer/Word2007/Style/SectionTest.php
@@ -0,0 +1,59 @@
+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';
+ self::assertEquals('144', $doc->getElementAttribute($path, 'w:top'));
+ self::assertEquals('432', $doc->getElementAttribute($path, 'w:right'));
+ self::assertEquals('576', $doc->getElementAttribute($path, 'w:bottom'));
+ self::assertEquals('288', $doc->getElementAttribute($path, 'w:left'));
+ }
+}
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 @@
+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'));
+ }
+}
diff --git a/tests/PhpWord/Writer/Word2007/Style/TableTest.php b/tests/PhpWordTests/Writer/Word2007/Style/TableTest.php
similarity index 54%
rename from tests/PhpWord/Writer/Word2007/Style/TableTest.php
rename to tests/PhpWordTests/Writer/Word2007/Style/TableTest.php
index 8e5cb63415..b10d836568 100644
--- a/tests/PhpWord/Writer/Word2007/Style/TableTest.php
+++ b/tests/PhpWordTests/Writer/Word2007/Style/TableTest.php
@@ -1,4 +1,5 @@
setLayout(Table::LAYOUT_FIXED);
@@ -55,14 +57,14 @@ public function testTableLayout()
$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'));
+ self::assertTrue($doc->elementExists($path));
+ self::assertEquals(Table::LAYOUT_FIXED, $doc->getElementAttribute($path, 'w:type'));
}
/**
- * Test write styles
+ * Test write styles.
*/
- public function testCellSpacing()
+ public function testCellSpacing(): void
{
$tableStyle = new Table();
$tableStyle->setCellSpacing(10.3);
@@ -75,28 +77,28 @@ public function testCellSpacing()
$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(TblWidth::TWIP, $doc->getElementAttribute($path, 'w:type'));
+ self::assertTrue($doc->elementExists($path));
+ self::assertEquals(10.3, $doc->getElementAttribute($path, 'w:w'));
+ self::assertEquals(TblWidth::TWIP, $doc->getElementAttribute($path, 'w:type'));
}
/**
- * Test write table position
+ * Test write table position.
*/
- public function testTablePosition()
+ public function testTablePosition(): void
{
- $tablePosition = array(
- 'leftFromText' => 10,
- 'rightFromText' => 20,
- 'topFromText' => 30,
+ $tablePosition = [
+ '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,
- );
+ '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);
@@ -108,20 +110,20 @@ public function testTablePosition()
$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'));
+ self::assertTrue($doc->elementExists($path));
+ self::assertEquals(10, $doc->getElementAttribute($path, 'w:leftFromText'));
+ self::assertEquals(20, $doc->getElementAttribute($path, 'w:rightFromText'));
+ self::assertEquals(30, $doc->getElementAttribute($path, 'w:topFromText'));
+ self::assertEquals(40, $doc->getElementAttribute($path, 'w:bottomFromText'));
+ self::assertEquals(TablePosition::VANCHOR_PAGE, $doc->getElementAttribute($path, 'w:vertAnchor'));
+ self::assertEquals(TablePosition::HANCHOR_MARGIN, $doc->getElementAttribute($path, 'w:horzAnchor'));
+ self::assertEquals(TablePosition::XALIGN_CENTER, $doc->getElementAttribute($path, 'w:tblpXSpec'));
+ self::assertEquals(50, $doc->getElementAttribute($path, 'w:tblpX'));
+ self::assertEquals(TablePosition::YALIGN_TOP, $doc->getElementAttribute($path, 'w:tblpYSpec'));
+ self::assertEquals(60, $doc->getElementAttribute($path, 'w:tblpY'));
}
- public function testIndent()
+ public function testIndent(): void
{
$value = 100;
$type = TblWidth::TWIP;
@@ -137,12 +139,12 @@ public function testIndent()
$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'));
+ self::assertTrue($doc->elementExists($path));
+ self::assertSame($value, (int) $doc->getElementAttribute($path, 'w:w'));
+ self::assertSame($type, $doc->getElementAttribute($path, 'w:type'));
}
- public function testRigthToLeft()
+ public function testRigthToLeft(): void
{
$tableStyle = new Table();
$tableStyle->setBidiVisual(true);
@@ -155,7 +157,7 @@ public function testRigthToLeft()
$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'));
+ self::assertTrue($doc->elementExists($path));
+ self::assertEquals('1', $doc->getElementAttribute($path, 'w:val'));
}
}
diff --git a/tests/PhpWord/Writer/Word2007/StyleTest.php b/tests/PhpWordTests/Writer/Word2007/StyleTest.php
similarity index 51%
rename from tests/PhpWord/Writer/Word2007/StyleTest.php
rename to tests/PhpWordTests/Writer/Word2007/StyleTest.php
index 48cff8713a..0c0d0b854a 100644
--- a/tests/PhpWord/Writer/Word2007/StyleTest.php
+++ b/tests/PhpWordTests/Writer/Word2007/StyleTest.php
@@ -1,4 +1,5 @@
write();
- $this->assertEquals('', $xmlWriter->getData());
+ self::assertEquals('', $xmlWriter->getData());
}
}
/**
- * Test method exceptions
+ * Test method exceptions.
*/
- public function testMethodExceptions()
+ public function testMethodExceptionsFrame(): void
{
- $styles = array(
- '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();
- $this->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/PhpWord/Writer/Word2007Test.php b/tests/PhpWordTests/Writer/Word2007Test.php
similarity index 52%
rename from tests/PhpWord/Writer/Word2007Test.php
rename to tests/PhpWordTests/Writer/Word2007Test.php
index 563475b47b..64f6a29b52 100644
--- a/tests/PhpWord/Writer/Word2007Test.php
+++ b/tests/PhpWordTests/Writer/Word2007Test.php
@@ -1,4 +1,5 @@
'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(
+ self::assertInstanceOf(
"PhpOffice\\PhpWord\\Writer\\Word2007\\Part\\{$type}",
$object->getWriterPart($part)
);
- $this->assertInstanceOf(
+ self::assertInstanceOf(
'PhpOffice\\PhpWord\\Writer\\Word2007',
$object->getWriterPart($part)->getParentWriter()
);
@@ -71,15 +75,15 @@ public function testConstruct()
}
/**
- * Save
+ * Save.
*/
- public function testSave()
+ public function testSave(): void
{
$localImage = __DIR__ . '/../_files/images/earth.jpg';
$remoteImage = self::getRemoteGifImageUrl();
$phpWord = new PhpWord();
- $phpWord->addFontStyle('Font', array('size' => 11));
- $phpWord->addParagraphStyle('Paragraph', array('alignment' => Jc::CENTER));
+ $phpWord->addFontStyle('Font', ['size' => 11]);
+ $phpWord->addParagraphStyle('Paragraph', ['alignment' => Jc::CENTER]);
$section = $phpWord->addSection();
$section->addText('Test 1', 'Font', 'Paragraph');
$section->addTextBreak();
@@ -98,15 +102,15 @@ public function testSave()
$file = __DIR__ . '/../_files/temp.docx';
$writer->save($file);
- $this->assertFileExists($file);
+ self::assertFileExists($file);
unlink($file);
}
/**
- * Save using disk caching
+ * Save using disk caching.
*/
- public function testSaveUseDiskCaching()
+ public function testSaveUseDiskCaching(): void
{
$phpWord = new PhpWord();
$section = $phpWord->addSection();
@@ -115,28 +119,33 @@ public function testSaveUseDiskCaching()
$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);
- $this->assertFileExists($file);
+ self::assertFileExists($file);
unlink($file);
+ TestHelperDOCX::deleteDir($dir);
}
/**
- * Check content types
+ * Check content types.
*/
- public function testCheckContentTypes()
+ public function testCheckContentTypes(): void
{
- $images = array(
- 'mars_noext_jpg' => '1.jpg',
- 'mars.jpg' => '2.jpg',
- 'mario.gif' => '3.gif',
- 'firefox.png' => '4.png',
- 'duke_nukem.bmp' => '5.bmp',
+ $images = [
+ 'mars_noext_jpg' => '1.jpg',
+ 'mars.jpg' => '2.jpg',
+ 'mario.gif' => '3.gif',
+ 'firefox.png' => '4.png',
+ 'duke_nukem.bmp' => '5.bmp',
'angela_merkel.tif' => '6.tif',
- );
+ ];
$phpWord = new PhpWord();
$section = $phpWord->addSection();
foreach ($images as $source => $target) {
@@ -147,7 +156,7 @@ public function testCheckContentTypes()
$mediaPath = $doc->getPath() . '/word/media';
foreach ($images as $source => $target) {
- $this->assertFileEquals(
+ self::assertFileEquals(
__DIR__ . "/../_files/images/{$source}",
$mediaPath . "/section_image{$target}"
);
@@ -155,41 +164,62 @@ public function testCheckContentTypes()
}
/**
- * Get writer part return null value
+ * Get writer part return null value.
*/
- public function testGetWriterPartNull()
+ public function testGetWriterPartNull(): void
{
$object = new Word2007();
- $this->assertNull($object->getWriterPart());
+ self::assertNull($object->getWriterPart());
}
/**
- * Set/get use disk caching
+ * Set/get use disk caching.
*/
- public function testSetGetUseDiskCaching()
+ public function testSetGetUseDiskCaching(): void
{
- $this->setOutputCallback(function () {
- });
$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');
-
- $this->assertTrue($object->isUseDiskCaching());
+ $contents = ob_get_contents();
+ self::assertTrue(ob_end_clean());
+ self::assertTrue($object->isUseDiskCaching());
+ self::assertNotEmpty($contents);
}
/**
- * Use disk caching exception
- *
- * @expectedException \PhpOffice\PhpWord\Exception\Exception
+ * Use disk caching exception.
*/
- public function testSetUseDiskCachingException()
+ public function testSetUseDiskCachingException(): void
{
- $dir = implode(DIRECTORY_SEPARATOR, array(PHPWORD_TESTS_BASE_DIR, 'foo'));
+ $this->expectException(\PhpOffice\PhpWord\Exception\Exception::class);
+ $dir = implode(DIRECTORY_SEPARATOR, [PHPWORD_TESTS_BASE_DIR, 'foo']);
$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);
+ }
}
diff --git a/tests/PhpWordTests/XmlDocument.php b/tests/PhpWordTests/XmlDocument.php
new file mode 100644
index 0000000000..8c865932ba
--- /dev/null
+++ b/tests/PhpWordTests/XmlDocument.php
@@ -0,0 +1,214 @@
+path = realpath($path);
+ }
+
+ /**
+ * Get default file.
+ */
+ public function getDefaultFile(): string
+ {
+ return $this->defaultFile;
+ }
+
+ /**
+ * Set default file.
+ */
+ public function setDefaultFile(string $file): string
+ {
+ $temp = $this->defaultFile;
+
+ $this->defaultFile = $file;
+
+ return $temp;
+ }
+
+ /**
+ * Get file name.
+ */
+ public function getFile(): string
+ {
+ return $this->file;
+ }
+
+ /**
+ * Get path.
+ */
+ public function getPath(): string
+ {
+ return $this->path;
+ }
+
+ /**
+ * Get DOM from file.
+ */
+ public function getFileDom(string $file = ''): DOMDocument
+ {
+ if (!$file) {
+ $file = $this->defaultFile;
+ }
+ if (null !== $this->dom && $file === $this->file) {
+ return $this->dom;
+ }
+
+ $this->xpath = null;
+ $this->file = $file;
+
+ $file = $this->path . '/' . $file;
+ if (\PHP_VERSION_ID < 80000) {
+ $orignalLibEntityLoader = libxml_disable_entity_loader(false);
+ }
+ $this->dom = new DOMDocument();
+ $this->dom->load($file);
+ if (\PHP_VERSION_ID < 80000) {
+ libxml_disable_entity_loader($orignalLibEntityLoader);
+ }
+
+ return $this->dom;
+ }
+
+ /**
+ * Get node list.
+ *
+ * @return DOMNodeList
+ */
+ public function getNodeList(string $path, string $file = ''): DOMNodeList
+ {
+ if (!$file) {
+ $file = $this->defaultFile;
+ }
+ if (null === $this->dom || $file !== $this->file) {
+ $this->getFileDom($file);
+ }
+
+ 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);
+ }
+
+ /**
+ * Get element.
+ */
+ public function getElement(string $path, string $file = ''): ?DOMElement
+ {
+ return $this->getNodeList($path, $file)->item(0);
+ }
+
+ /**
+ * Get element attribute.
+ */
+ public function getElementAttribute(string $path, string $attribute, string $file = ''): string
+ {
+ 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.
+ */
+ public function elementExists(string $path, string $file = ''): bool
+ {
+ $nodeList = $this->getNodeList($path, $file);
+
+ return $nodeList->length != 0;
+ }
+
+ /**
+ * Returns the xml, or part of it as a formatted string.
+ *
+ * @return false|string
+ */
+ public function printXml(string $path = '/', string $file = '')
+ {
+ $element = $this->getElement($path, $file);
+
+ $newdoc = new DOMDocument();
+ $newdoc->formatOutput = true;
+ $newdoc->preserveWhiteSpace = false;
+ $node = $newdoc->importNode($element, true);
+ $newdoc->appendChild($node);
+
+ return $newdoc->saveXML($node);
+ }
+}
diff --git a/tests/PhpWordTests/_files/documents/docChinese.doc b/tests/PhpWordTests/_files/documents/docChinese.doc
new file mode 100644
index 0000000000..db245953e5
Binary files /dev/null and b/tests/PhpWordTests/_files/documents/docChinese.doc differ
diff --git a/tests/PhpWordTests/_files/documents/docCzech.doc b/tests/PhpWordTests/_files/documents/docCzech.doc
new file mode 100644
index 0000000000..8def81b13e
Binary files /dev/null and b/tests/PhpWordTests/_files/documents/docCzech.doc differ
diff --git a/tests/PhpWordTests/_files/documents/docSlovak.doc b/tests/PhpWordTests/_files/documents/docSlovak.doc
new file mode 100644
index 0000000000..dede581e55
Binary files /dev/null and b/tests/PhpWordTests/_files/documents/docSlovak.doc differ
diff --git a/tests/PhpWord/_files/documents/reader-2011.docx b/tests/PhpWordTests/_files/documents/reader-2011.docx
similarity index 100%
rename from tests/PhpWord/_files/documents/reader-2011.docx
rename to tests/PhpWordTests/_files/documents/reader-2011.docx
diff --git a/tests/PhpWordTests/_files/documents/reader-comments.docx b/tests/PhpWordTests/_files/documents/reader-comments.docx
new file mode 100644
index 0000000000..4748da6838
Binary files /dev/null and b/tests/PhpWordTests/_files/documents/reader-comments.docx differ
diff --git a/tests/PhpWordTests/_files/documents/reader-formula.docx b/tests/PhpWordTests/_files/documents/reader-formula.docx
new file mode 100644
index 0000000000..0e40f6672c
Binary files /dev/null and b/tests/PhpWordTests/_files/documents/reader-formula.docx differ
diff --git a/tests/PhpWordTests/_files/documents/reader-formula.odt b/tests/PhpWordTests/_files/documents/reader-formula.odt
new file mode 100644
index 0000000000..f94c44afbb
Binary files /dev/null and b/tests/PhpWordTests/_files/documents/reader-formula.odt differ
diff --git a/tests/PhpWordTests/_files/documents/reader-styles.docx b/tests/PhpWordTests/_files/documents/reader-styles.docx
new file mode 100644
index 0000000000..b02cf73c5f
Binary files /dev/null and b/tests/PhpWordTests/_files/documents/reader-styles.docx differ
diff --git a/tests/PhpWord/_files/documents/reader.doc b/tests/PhpWordTests/_files/documents/reader.doc
similarity index 100%
rename from tests/PhpWord/_files/documents/reader.doc
rename to tests/PhpWordTests/_files/documents/reader.doc
diff --git a/tests/PhpWord/_files/documents/reader.docx b/tests/PhpWordTests/_files/documents/reader.docx
similarity index 100%
rename from tests/PhpWord/_files/documents/reader.docx
rename to tests/PhpWordTests/_files/documents/reader.docx
diff --git a/tests/PhpWord/_files/documents/reader.docx.zip b/tests/PhpWordTests/_files/documents/reader.docx.zip
similarity index 100%
rename from tests/PhpWord/_files/documents/reader.docx.zip
rename to tests/PhpWordTests/_files/documents/reader.docx.zip
diff --git a/tests/PhpWordTests/_files/documents/reader.font-halfpoint.doc b/tests/PhpWordTests/_files/documents/reader.font-halfpoint.doc
new file mode 100644
index 0000000000..94fc5ed8fd
Binary files /dev/null and b/tests/PhpWordTests/_files/documents/reader.font-halfpoint.doc differ
diff --git a/tests/PhpWord/_files/documents/reader.html b/tests/PhpWordTests/_files/documents/reader.html
similarity index 100%
rename from tests/PhpWord/_files/documents/reader.html
rename to tests/PhpWordTests/_files/documents/reader.html
diff --git a/tests/PhpWord/_files/documents/reader.odt b/tests/PhpWordTests/_files/documents/reader.odt
similarity index 100%
rename from tests/PhpWord/_files/documents/reader.odt
rename to tests/PhpWordTests/_files/documents/reader.odt
diff --git a/tests/PhpWord/_files/documents/reader.rtf b/tests/PhpWordTests/_files/documents/reader.rtf
similarity index 100%
rename from tests/PhpWord/_files/documents/reader.rtf
rename to tests/PhpWordTests/_files/documents/reader.rtf
diff --git a/tests/PhpWord/_files/documents/sheet.xls b/tests/PhpWordTests/_files/documents/sheet.xls
similarity index 100%
rename from tests/PhpWord/_files/documents/sheet.xls
rename to tests/PhpWordTests/_files/documents/sheet.xls
diff --git a/tests/PhpWord/_files/documents/without_table_macros.docx b/tests/PhpWordTests/_files/documents/without_table_macros.docx
similarity index 100%
rename from tests/PhpWord/_files/documents/without_table_macros.docx
rename to tests/PhpWordTests/_files/documents/without_table_macros.docx
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 0000000000..eb0fa20764
Binary files /dev/null and b/tests/PhpWordTests/_files/documents/word.2493.nosection.odt differ
diff --git a/tests/PhpWord/_files/images/PhpWord.png b/tests/PhpWordTests/_files/images/PhpWord.png
similarity index 100%
rename from tests/PhpWord/_files/images/PhpWord.png
rename to tests/PhpWordTests/_files/images/PhpWord.png
diff --git a/tests/PhpWord/_files/images/alexz-johnson.pcx b/tests/PhpWordTests/_files/images/alexz-johnson.pcx
similarity index 100%
rename from tests/PhpWord/_files/images/alexz-johnson.pcx
rename to tests/PhpWordTests/_files/images/alexz-johnson.pcx
diff --git a/tests/PhpWord/_files/images/angela_merkel.tif b/tests/PhpWordTests/_files/images/angela_merkel.tif
similarity index 100%
rename from tests/PhpWord/_files/images/angela_merkel.tif
rename to tests/PhpWordTests/_files/images/angela_merkel.tif
diff --git a/tests/PhpWord/_files/images/duke_nukem.bmp b/tests/PhpWordTests/_files/images/duke_nukem.bmp
similarity index 100%
rename from tests/PhpWord/_files/images/duke_nukem.bmp
rename to tests/PhpWordTests/_files/images/duke_nukem.bmp
diff --git a/tests/PhpWord/_files/images/earth.jpg b/tests/PhpWordTests/_files/images/earth.jpg
similarity index 100%
rename from tests/PhpWord/_files/images/earth.jpg
rename to tests/PhpWordTests/_files/images/earth.jpg
diff --git a/tests/PhpWord/_files/images/firefox.png b/tests/PhpWordTests/_files/images/firefox.png
similarity index 100%
rename from tests/PhpWord/_files/images/firefox.png
rename to tests/PhpWordTests/_files/images/firefox.png
diff --git a/tests/PhpWord/_files/images/mario.gif b/tests/PhpWordTests/_files/images/mario.gif
similarity index 100%
rename from tests/PhpWord/_files/images/mario.gif
rename to tests/PhpWordTests/_files/images/mario.gif
diff --git a/tests/PhpWord/_files/images/mars.jpg b/tests/PhpWordTests/_files/images/mars.jpg
similarity index 100%
rename from tests/PhpWord/_files/images/mars.jpg
rename to tests/PhpWordTests/_files/images/mars.jpg
diff --git a/tests/PhpWord/_files/images/mars_noext_jpg b/tests/PhpWordTests/_files/images/mars_noext_jpg
similarity index 100%
rename from tests/PhpWord/_files/images/mars_noext_jpg
rename to tests/PhpWordTests/_files/images/mars_noext_jpg
diff --git a/tests/PhpWord/_files/images/new-php-logo.png b/tests/PhpWordTests/_files/images/new-php-logo
similarity index 100%
rename from tests/PhpWord/_files/images/new-php-logo.png
rename to tests/PhpWordTests/_files/images/new-php-logo
diff --git a/tests/PhpWordTests/_files/images/new-php-logo.png b/tests/PhpWordTests/_files/images/new-php-logo.png
new file mode 100644
index 0000000000..6649079930
Binary files /dev/null and b/tests/PhpWordTests/_files/images/new-php-logo.png differ
diff --git a/tests/PhpWord/_files/templates/blank.docx b/tests/PhpWordTests/_files/templates/blank.docx
similarity index 100%
rename from tests/PhpWord/_files/templates/blank.docx
rename to tests/PhpWordTests/_files/templates/blank.docx
diff --git a/tests/PhpWord/_files/templates/clone-delete-block.docx b/tests/PhpWordTests/_files/templates/clone-delete-block.docx
similarity index 100%
rename from tests/PhpWord/_files/templates/clone-delete-block.docx
rename to tests/PhpWordTests/_files/templates/clone-delete-block.docx
diff --git a/tests/PhpWordTests/_files/templates/clone-merge-with-custom-macro.docx b/tests/PhpWordTests/_files/templates/clone-merge-with-custom-macro.docx
new file mode 100644
index 0000000000..e023ed0765
Binary files /dev/null and b/tests/PhpWordTests/_files/templates/clone-merge-with-custom-macro.docx differ
diff --git a/tests/PhpWord/_files/templates/clone-merge.docx b/tests/PhpWordTests/_files/templates/clone-merge.docx
similarity index 100%
rename from tests/PhpWord/_files/templates/clone-merge.docx
rename to tests/PhpWordTests/_files/templates/clone-merge.docx
diff --git a/tests/PhpWord/_files/templates/corrupted_main_document_part.docx b/tests/PhpWordTests/_files/templates/corrupted_main_document_part.docx
similarity index 100%
rename from tests/PhpWord/_files/templates/corrupted_main_document_part.docx
rename to tests/PhpWordTests/_files/templates/corrupted_main_document_part.docx
diff --git a/tests/PhpWordTests/_files/templates/delete-row.docx b/tests/PhpWordTests/_files/templates/delete-row.docx
new file mode 100644
index 0000000000..dd8d8a3188
Binary files /dev/null and b/tests/PhpWordTests/_files/templates/delete-row.docx differ
diff --git a/tests/PhpWordTests/_files/templates/document22-with-custom-macro-xml.docx b/tests/PhpWordTests/_files/templates/document22-with-custom-macro-xml.docx
new file mode 100644
index 0000000000..5aba782b65
Binary files /dev/null and b/tests/PhpWordTests/_files/templates/document22-with-custom-macro-xml.docx differ
diff --git a/tests/PhpWord/_files/templates/document22-xml.docx b/tests/PhpWordTests/_files/templates/document22-xml.docx
similarity index 100%
rename from tests/PhpWord/_files/templates/document22-xml.docx
rename to tests/PhpWordTests/_files/templates/document22-xml.docx
diff --git a/tests/PhpWordTests/_files/templates/extract-variable.docx b/tests/PhpWordTests/_files/templates/extract-variable.docx
new file mode 100644
index 0000000000..f95ec61862
Binary files /dev/null and b/tests/PhpWordTests/_files/templates/extract-variable.docx differ
diff --git a/tests/PhpWordTests/_files/templates/header-footer-with-custom-macro.docx b/tests/PhpWordTests/_files/templates/header-footer-with-custom-macro.docx
new file mode 100644
index 0000000000..19d5669335
Binary files /dev/null and b/tests/PhpWordTests/_files/templates/header-footer-with-custom-macro.docx differ
diff --git a/tests/PhpWord/_files/templates/header-footer.docx b/tests/PhpWordTests/_files/templates/header-footer.docx
similarity index 100%
rename from tests/PhpWord/_files/templates/header-footer.docx
rename to tests/PhpWordTests/_files/templates/header-footer.docx
diff --git a/tests/PhpWord/_files/templates/with_table_macros.docx b/tests/PhpWordTests/_files/templates/with_table_macros.docx
similarity index 100%
rename from tests/PhpWord/_files/templates/with_table_macros.docx
rename to tests/PhpWordTests/_files/templates/with_table_macros.docx
diff --git a/tests/PhpWordTests/_files/xml/reader.zip b/tests/PhpWordTests/_files/xml/reader.zip
new file mode 100644
index 0000000000..dbe69cbbc0
Binary files /dev/null and b/tests/PhpWordTests/_files/xml/reader.zip differ
diff --git a/tests/PhpWord/_files/xsl/passthrough.xsl b/tests/PhpWordTests/_files/xsl/passthrough.xsl
similarity index 100%
rename from tests/PhpWord/_files/xsl/passthrough.xsl
rename to tests/PhpWordTests/_files/xsl/passthrough.xsl
diff --git a/tests/PhpWord/_files/xsl/remove_tables_by_needle.xsl b/tests/PhpWordTests/_files/xsl/remove_tables_by_needle.xsl
similarity index 100%
rename from tests/PhpWord/_files/xsl/remove_tables_by_needle.xsl
rename to tests/PhpWordTests/_files/xsl/remove_tables_by_needle.xsl
diff --git a/tests/bootstrap.php b/tests/bootstrap.php
index c1681bcd6f..d94d68d880 100644
--- a/tests/bootstrap.php
+++ b/tests/bootstrap.php
@@ -1,4 +1,5 @@