diff --git a/.scrutinizer.yml b/.scrutinizer.yml index 2b395afd26..d1fe59618d 100644 --- a/.scrutinizer.yml +++ b/.scrutinizer.yml @@ -3,6 +3,12 @@ build: analysis: tests: override: [php-scrutinizer-run] + environment: + php: + version: '7.4' + pecl_extensions: + - zip + filter: excluded_paths: [ 'vendor/*', 'tests/*', 'samples/*', 'src/PhpWord/Shared/PCLZip/*' ] diff --git a/.travis.yml b/.travis.yml index acdf95cc34..c368913dbe 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,29 +11,26 @@ php: - 7.1 - 7.2 - 7.3 - - 7.4snapshot + - 7.4 + - 8.0 matrix: include: - php: 5.3 dist: precise - env: COMPOSER_MEMORY_LIMIT=3G - php: 5.4 dist: trusty - php: 5.5 dist: trusty - php: 7.0 env: COVERAGE=1 - - php: 7.3 - env: DEPENDENCIES="--ignore-platform-reqs" exclude: - php: 5.3 + dist: xenial - php: 5.4 + dist: xenial - php: 5.5 - - php: 7.0 - - php: 7.3 - allow_failures: - - php: 7.4snapshot + dist: xenial cache: directories: @@ -55,7 +52,31 @@ before_script: - if [ -z "$COVERAGE" ]; then phpenv config-rm xdebug.ini || echo "xdebug not available" ; fi ## Composer - composer self-update + ## Composer in PHP versions 5.x requires 3 GB memory + - if [ ${TRAVIS_PHP_VERSION:0:2} == "5." ]; then export COMPOSER_MEMORY_LIMIT=3G ; fi + ## PHP 8 require PHPUnit 8 (ugly hack for support PHPUnit 7 and 8 together) + - | + if [[ ${TRAVIS_PHP_VERSION:0:2} == "8." ]] || [[ $TRAVIS_PHP_VERSION == "nightly" ]]; then + travis_wait composer remove phpunit/phpunit --dev --no-update --no-interaction + travis_wait composer require phpunit/phpunit ^8.0 --dev --no-update + fi + ## Install composer packages - travis_wait composer install --prefer-source $(if [ -n "$DEPENDENCIES" ]; then echo $DEPENDENCIES; fi) + ## PHP 8 require PHPUnit 8 (ugly hack for support PHPUnit 7 and 8 together) + - | + if [[ ${TRAVIS_PHP_VERSION:0:2} == "8." ]] || [[ $TRAVIS_PHP_VERSION == "nightly" ]]; then + find ./tests/ -name "*.php" -type f -exec sed -i -e 's/function setUpBeforeClass()$/function setUpBeforeClass(): void/' {} \; + find ./tests/ -name "*.php" -type f -exec sed -i -e 's/function tearDownAfterClass()$/function tearDownAfterClass(): void/' {} \; + find ./tests/ -name "*.php" -type f -exec sed -i -e 's/function setUp()$/function setUp(): void/' {} \; + find ./tests/ -name "*.php" -type f -exec sed -i -e 's/function tearDown()$/function tearDown(): void/' {} \; + + find ./tests/ -name "*.php" -type f -exec sed -i -e 's/->assertContains(/->assertStringContainsString(/' {} \; + find ./tests/ -name "*.php" -type f -exec sed -i -e 's/->assertNotContains(/->assertStringNotContainsString(/' {} \; + find ./tests/ -name "*.php" -type f -exec sed -i -e "s/->assertInternalType('array', /->assertIsArray(/" {} \; + + sed -i "s/\$this->addWarning('The @expectedException,/\/\/\$this->addWarning('The @expectedException,/" ./vendor/phpunit/phpunit/src/Framework/TestCase.php + sed -i "s/self::createWarning('The optional \$delta/\/\/self::createWarning('The optional \$delta/" ./vendor/phpunit/phpunit/src/Framework/Assert.php + fi ## PHPDocumentor ##- mkdir -p build/docs - mkdir -p build/coverage diff --git a/README.md b/README.md index b15f83d74e..30b008a28e 100644 --- a/README.md +++ b/README.md @@ -62,8 +62,7 @@ PHPWord requires the following: - PHP 5.3.3+ - [XML Parser extension](http://www.php.net/manual/en/xml.installation.php) -- [Zend\Escaper component](http://framework.zend.com/manual/current/en/modules/zend.escaper.introduction.html) -- [Zend\Stdlib component](http://framework.zend.com/manual/current/en/modules/zend.stdlib.hydrator.html) +- [Laminas Escaper component](https://docs.laminas.dev/laminas-escaper/intro/) - [Zip extension](http://php.net/manual/en/book.zip.php) (optional, used to write OOXML and ODF) - [GD extension](http://php.net/manual/en/book.image.php) (optional, used to add images) - [XMLWriter extension](http://php.net/manual/en/book.xmlwriter.php) (optional, used to write OOXML and ODF) diff --git a/composer.json b/composer.json index f5f751ec04..64363fe1e1 100644 --- a/composer.json +++ b/composer.json @@ -58,24 +58,26 @@ "fix": "Fixes issues found by PHP-CS" }, "require": { - "php": "^5.3.3 || ^7.0", + "php": "^5.3.3 || ^7.0 || ^8.0", "ext-xml": "*", - "zendframework/zend-escaper": "^2.2", - "phpoffice/common": "^0.2.9" + "laminas/laminas-escaper": "^2.2" }, "require-dev": { "ext-zip": "*", "ext-gd": "*", "phpunit/phpunit": "^4.8.36 || ^7.0", - "squizlabs/php_codesniffer": "^2.9", + "squizlabs/php_codesniffer": "^2.9 || ^3.5", "friendsofphp/php-cs-fixer": "^2.2", "phpmd/phpmd": "2.*", - "phploc/phploc": "2.* || 3.* || 4.*", - "dompdf/dompdf":"0.8.*", + "phploc/phploc": "2.* || 3.* || 4.* || 5.* || 6.* || 7.*", + "dompdf/dompdf":"0.8.* || 1.0.*", "tecnickcom/tcpdf": "6.*", - "mpdf/mpdf": "5.7.4 || 6.* || 7.*", + "mpdf/mpdf": "5.7.4 || 6.* || 7.* || 8.*", "php-coveralls/php-coveralls": "1.1.0 || ^2.0" }, + "replace": { + "laminas/laminas-zendframework-bridge": "*" + }, "suggest": { "ext-zip": "Allows writing OOXML and ODF", "ext-gd2": "Allows adding images", diff --git a/docs/general.rst b/docs/general.rst index f40a08c367..d4b9b99c45 100644 --- a/docs/general.rst +++ b/docs/general.rst @@ -130,6 +130,16 @@ To turn it on set ``outputEscapingEnabled`` option to ``true`` in your PHPWord c \PhpOffice\PhpWord\Settings::setOutputEscapingEnabled(true); +Default Paper +~~~~~~~~~~~~~ + +By default, all sections of the document will print on A4 paper. +You can alter the default paper by using the following function: + +.. code-block:: php + + \PhpOffice\PhpWord\Settings::setDefaultPaper('Letter'); + Default font ~~~~~~~~~~~~ diff --git a/docs/installing.rst b/docs/installing.rst index 2a9582d067..baf966bd0e 100644 --- a/docs/installing.rst +++ b/docs/installing.rst @@ -10,9 +10,7 @@ Mandatory: - PHP 5.3.3+ - `XML Parser `__ extension -- `Zend\\Escaper `__ component -- Zend\\Stdlib component -- `Zend\\Validator `__ component +- `Laminas Escaper `__ component Optional: diff --git a/docs/templates-processing.rst b/docs/templates-processing.rst index 5bc114549d..bac421c368 100644 --- a/docs/templates-processing.rst +++ b/docs/templates-processing.rst @@ -190,7 +190,7 @@ Finds a row in a table row identified by `$search` param and clones it as many t ['userId' => 1, 'userName' => 'Batman', 'userAddress' => 'Gotham City'], ['userId' => 2, 'userName' => 'Superman', 'userAddress' => 'Metropolis'], ]; - $templateProcessor->cloneRowAndSetValues('userId', ); + $templateProcessor->cloneRowAndSetValues('userId', $values); Will result in diff --git a/phpmd.xml.dist b/phpmd.xml.dist index 2077e02b04..cfb9353b57 100644 --- a/phpmd.xml.dist +++ b/phpmd.xml.dist @@ -5,6 +5,8 @@ xsi:schemaLocation="http://pmd.sf.net/ruleset/1.0.0 http://pmd.sf.net/ruleset_xml_schema.xsd" xsi:noNamespaceSchemaLocation="http://pmd.sf.net/ruleset_xml_schema.xsd"> + + diff --git a/phpword.ini.dist b/phpword.ini.dist index 0f4cc358df..f3f66dbe2e 100644 --- a/phpword.ini.dist +++ b/phpword.ini.dist @@ -14,3 +14,7 @@ outputEscapingEnabled = false defaultFontName = Arial defaultFontSize = 10 + +[Paper] + +defaultPaper = "A4" diff --git a/src/PhpWord/Element/AbstractContainer.php b/src/PhpWord/Element/AbstractContainer.php index 0c773dbe69..6a1ed93013 100644 --- a/src/PhpWord/Element/AbstractContainer.php +++ b/src/PhpWord/Element/AbstractContainer.php @@ -109,6 +109,7 @@ public function __call($function, $args) } else { // All other elements array_unshift($args, $element); // Prepend element name to the beginning of args array + return call_user_func_array(array($this, 'addElement'), $args); } } diff --git a/src/PhpWord/Element/Bookmark.php b/src/PhpWord/Element/Bookmark.php index 16b020d741..856f68600b 100644 --- a/src/PhpWord/Element/Bookmark.php +++ b/src/PhpWord/Element/Bookmark.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWord\Element; -use PhpOffice\Common\Text as CommonText; +use PhpOffice\PhpWord\Shared\Text as SharedText; /** * Bookmark element @@ -45,7 +45,7 @@ class Bookmark extends AbstractElement */ public function __construct($name = '') { - $this->name = CommonText::toUTF8($name); + $this->name = SharedText::toUTF8($name); } /** diff --git a/src/PhpWord/Element/CheckBox.php b/src/PhpWord/Element/CheckBox.php index f3e87176ef..beabf8a0a8 100644 --- a/src/PhpWord/Element/CheckBox.php +++ b/src/PhpWord/Element/CheckBox.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWord\Element; -use PhpOffice\Common\Text as CommonText; +use PhpOffice\PhpWord\Shared\Text as SharedText; /** * Check box element @@ -55,7 +55,7 @@ public function __construct($name = null, $text = null, $fontStyle = null, $para */ public function setName($name) { - $this->name = CommonText::toUTF8($name); + $this->name = SharedText::toUTF8($name); return $this; } diff --git a/src/PhpWord/Element/Image.php b/src/PhpWord/Element/Image.php index bae87ff5d8..2e25fd18e5 100644 --- a/src/PhpWord/Element/Image.php +++ b/src/PhpWord/Element/Image.php @@ -454,7 +454,7 @@ private function setSourceType() } else { $this->sourceType = self::SOURCE_GD; } - } elseif (@file_exists($this->source)) { + } elseif ((strpos($this->source, chr(0)) === false) && @file_exists($this->source)) { $this->memoryImage = false; $this->sourceType = self::SOURCE_LOCAL; } else { diff --git a/src/PhpWord/Element/Link.php b/src/PhpWord/Element/Link.php index 2bec32ddc4..25a87feecb 100644 --- a/src/PhpWord/Element/Link.php +++ b/src/PhpWord/Element/Link.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWord\Element; -use PhpOffice\Common\Text as CommonText; +use PhpOffice\PhpWord\Shared\Text as SharedText; use PhpOffice\PhpWord\Style\Font; use PhpOffice\PhpWord\Style\Paragraph; @@ -79,8 +79,8 @@ class Link extends AbstractElement */ public function __construct($source, $text = null, $fontStyle = null, $paragraphStyle = null, $internal = false) { - $this->source = CommonText::toUTF8($source); - $this->text = is_null($text) ? $this->source : CommonText::toUTF8($text); + $this->source = SharedText::toUTF8($source); + $this->text = is_null($text) ? $this->source : SharedText::toUTF8($text); $this->fontStyle = $this->setNewStyle(new Font('text'), $fontStyle); $this->paragraphStyle = $this->setNewStyle(new Paragraph(), $paragraphStyle); $this->internal = $internal; diff --git a/src/PhpWord/Element/ListItem.php b/src/PhpWord/Element/ListItem.php index 8b064c47b5..40381de0d9 100644 --- a/src/PhpWord/Element/ListItem.php +++ b/src/PhpWord/Element/ListItem.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWord\Element; -use PhpOffice\Common\Text as CommonText; +use PhpOffice\PhpWord\Shared\Text as SharedText; use PhpOffice\PhpWord\Style\ListItem as ListItemStyle; /** @@ -57,7 +57,7 @@ class ListItem extends AbstractElement */ public function __construct($text, $depth = 0, $fontStyle = null, $listStyle = null, $paragraphStyle = null) { - $this->textObject = new Text(CommonText::toUTF8($text), $fontStyle, $paragraphStyle); + $this->textObject = new Text(SharedText::toUTF8($text), $fontStyle, $paragraphStyle); $this->depth = $depth; // Version >= 0.10.0 will pass numbering style name. Older version will use old method diff --git a/src/PhpWord/Element/PreserveText.php b/src/PhpWord/Element/PreserveText.php index 374f1a9984..c0e64268ba 100644 --- a/src/PhpWord/Element/PreserveText.php +++ b/src/PhpWord/Element/PreserveText.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWord\Element; -use PhpOffice\Common\Text as CommonText; +use PhpOffice\PhpWord\Shared\Text as SharedText; use PhpOffice\PhpWord\Style\Font; use PhpOffice\PhpWord\Style\Paragraph; @@ -59,7 +59,7 @@ public function __construct($text = null, $fontStyle = null, $paragraphStyle = n $this->fontStyle = $this->setNewStyle(new Font('text'), $fontStyle); $this->paragraphStyle = $this->setNewStyle(new Paragraph(), $paragraphStyle); - $this->text = CommonText::toUTF8($text); + $this->text = SharedText::toUTF8($text); $matches = preg_split('/({.*?})/', $this->text, null, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY); if (isset($matches[0])) { $this->text = $matches; diff --git a/src/PhpWord/Element/Section.php b/src/PhpWord/Element/Section.php index b6da9f3b9d..caf2ca2738 100644 --- a/src/PhpWord/Element/Section.php +++ b/src/PhpWord/Element/Section.php @@ -157,6 +157,8 @@ public function getFootnoteProperties() * @deprecated Use the `getFootnoteProperties` method instead * * @return FootnoteProperties + * + * @codeCoverageIgnore */ public function getFootnotePropoperties() { diff --git a/src/PhpWord/Element/Text.php b/src/PhpWord/Element/Text.php index f4d7f08185..1ad497b08d 100644 --- a/src/PhpWord/Element/Text.php +++ b/src/PhpWord/Element/Text.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWord\Element; -use PhpOffice\Common\Text as CommonText; +use PhpOffice\PhpWord\Shared\Text as SharedText; use PhpOffice\PhpWord\Style\Font; use PhpOffice\PhpWord\Style\Paragraph; @@ -136,7 +136,7 @@ public function getParagraphStyle() */ public function setText($text) { - $this->text = CommonText::toUTF8($text); + $this->text = SharedText::toUTF8($text); return $this; } diff --git a/src/PhpWord/Element/Title.php b/src/PhpWord/Element/Title.php index d01f7f339d..f061b3d568 100644 --- a/src/PhpWord/Element/Title.php +++ b/src/PhpWord/Element/Title.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWord\Element; -use PhpOffice\Common\Text as CommonText; +use PhpOffice\PhpWord\Shared\Text as SharedText; use PhpOffice\PhpWord\Style; /** @@ -62,7 +62,7 @@ class Title extends AbstractElement public function __construct($text, $depth = 1) { if (is_string($text)) { - $this->text = CommonText::toUTF8($text); + $this->text = SharedText::toUTF8($text); } elseif ($text instanceof TextRun) { $this->text = $text; } else { diff --git a/src/PhpWord/Metadata/Protection.php b/src/PhpWord/Metadata/Protection.php index 15aa3ff189..a46d43b945 100644 --- a/src/PhpWord/Metadata/Protection.php +++ b/src/PhpWord/Metadata/Protection.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWord\Metadata; -use PhpOffice\Common\Microsoft\PasswordEncoder; +use PhpOffice\PhpWord\Shared\Microsoft\PasswordEncoder; use PhpOffice\PhpWord\SimpleType\DocProtect; /** diff --git a/src/PhpWord/Reader/MsDoc.php b/src/PhpWord/Reader/MsDoc.php index 1a9e4988bf..b4c194ca2a 100644 --- a/src/PhpWord/Reader/MsDoc.php +++ b/src/PhpWord/Reader/MsDoc.php @@ -17,8 +17,8 @@ namespace PhpOffice\PhpWord\Reader; -use PhpOffice\Common\Drawing; use PhpOffice\PhpWord\PhpWord; +use PhpOffice\PhpWord\Shared\Drawing; use PhpOffice\PhpWord\Shared\OLERead; use PhpOffice\PhpWord\Style; @@ -1581,7 +1581,7 @@ private function readPrl($data, $pos, $cbNum) // Variables $sprmCPicLocation = null; $sprmCFData = null; - $sprmCFSpec = null; + //$sprmCFSpec = null; do { // Variables @@ -1830,7 +1830,7 @@ private function readPrl($data, $pos, $cbNum) break; // sprmCFSpec case 0x55: - $sprmCFSpec = $operand; + //$sprmCFSpec = $operand; break; // sprmCFtcBi case 0x5E: @@ -2094,11 +2094,11 @@ private function readPrl($data, $pos, $cbNum) $sprmCPicLocation += 1; // stPicName - $stPicName = ''; + //$stPicName = ''; for ($inc = 0; $inc <= $cchPicName; $inc++) { - $chr = self::getInt1d($this->dataData, $sprmCPicLocation); + //$chr = self::getInt1d($this->dataData, $sprmCPicLocation); $sprmCPicLocation += 1; - $stPicName .= chr($chr); + //$stPicName .= chr($chr); } } @@ -2143,11 +2143,11 @@ private function readPrl($data, $pos, $cbNum) $sprmCPicLocation += 1; // nameData if ($cbName > 0) { - $nameData = ''; + //$nameData = ''; for ($inc = 0; $inc <= ($cbName / 2); $inc++) { - $chr = self::getInt2d($this->dataData, $sprmCPicLocation); + //$chr = self::getInt2d($this->dataData, $sprmCPicLocation); $sprmCPicLocation += 2; - $nameData .= chr($chr); + //$nameData .= chr($chr); } } // embeddedBlip diff --git a/src/PhpWord/Reader/ODText.php b/src/PhpWord/Reader/ODText.php index 0b58dc50e1..d0aa9138fa 100644 --- a/src/PhpWord/Reader/ODText.php +++ b/src/PhpWord/Reader/ODText.php @@ -17,8 +17,8 @@ namespace PhpOffice\PhpWord\Reader; -use PhpOffice\Common\XMLReader; use PhpOffice\PhpWord\PhpWord; +use PhpOffice\PhpWord\Shared\XMLReader; /** * Reader for ODText diff --git a/src/PhpWord/Reader/ODText/Content.php b/src/PhpWord/Reader/ODText/Content.php index 9dfd645320..cec064181f 100644 --- a/src/PhpWord/Reader/ODText/Content.php +++ b/src/PhpWord/Reader/ODText/Content.php @@ -17,9 +17,9 @@ namespace PhpOffice\PhpWord\Reader\ODText; -use PhpOffice\Common\XMLReader; use PhpOffice\PhpWord\Element\TrackChange; use PhpOffice\PhpWord\PhpWord; +use PhpOffice\PhpWord\Shared\XMLReader; /** * Content reader diff --git a/src/PhpWord/Reader/ODText/Meta.php b/src/PhpWord/Reader/ODText/Meta.php index 8801a5439a..9a3d83414f 100644 --- a/src/PhpWord/Reader/ODText/Meta.php +++ b/src/PhpWord/Reader/ODText/Meta.php @@ -17,8 +17,8 @@ namespace PhpOffice\PhpWord\Reader\ODText; -use PhpOffice\Common\XMLReader; use PhpOffice\PhpWord\PhpWord; +use PhpOffice\PhpWord\Shared\XMLReader; /** * Meta reader diff --git a/src/PhpWord/Reader/Word2007.php b/src/PhpWord/Reader/Word2007.php index 52030ef8e0..699a4eadd1 100644 --- a/src/PhpWord/Reader/Word2007.php +++ b/src/PhpWord/Reader/Word2007.php @@ -17,8 +17,8 @@ namespace PhpOffice\PhpWord\Reader; -use PhpOffice\Common\XMLReader; use PhpOffice\PhpWord\PhpWord; +use PhpOffice\PhpWord\Shared\XMLReader; use PhpOffice\PhpWord\Shared\ZipArchive; /** diff --git a/src/PhpWord/Reader/Word2007/AbstractPart.php b/src/PhpWord/Reader/Word2007/AbstractPart.php index 06dfe37bb8..729c0b95b0 100644 --- a/src/PhpWord/Reader/Word2007/AbstractPart.php +++ b/src/PhpWord/Reader/Word2007/AbstractPart.php @@ -17,12 +17,12 @@ namespace PhpOffice\PhpWord\Reader\Word2007; -use PhpOffice\Common\XMLReader; use PhpOffice\PhpWord\ComplexType\TblWidth as TblWidthComplexType; use PhpOffice\PhpWord\Element\AbstractContainer; use PhpOffice\PhpWord\Element\TextRun; use PhpOffice\PhpWord\Element\TrackChange; use PhpOffice\PhpWord\PhpWord; +use PhpOffice\PhpWord\Shared\XMLReader; /** * Abstract part reader @@ -95,7 +95,7 @@ public function setRels($value) /** * Read w:p. * - * @param \PhpOffice\Common\XMLReader $xmlReader + * @param \PhpOffice\PhpWord\Shared\XMLReader $xmlReader * @param \DOMElement $domNode * @param \PhpOffice\PhpWord\Element\AbstractContainer $parent * @param string $docPart @@ -202,7 +202,7 @@ private function getHeadingDepth(array $paragraphStyle = null) /** * Read w:r. * - * @param \PhpOffice\Common\XMLReader $xmlReader + * @param \PhpOffice\PhpWord\Shared\XMLReader $xmlReader * @param \DOMElement $domNode * @param \PhpOffice\PhpWord\Element\AbstractContainer $parent * @param string $docPart @@ -292,6 +292,19 @@ protected function readRunChild(XMLReader $xmlReader, \DOMElement $node, Abstrac $parent->addTextBreak(); } elseif ($node->nodeName == 'w:tab') { $parent->addText("\t"); + } elseif ($node->nodeName == 'mc:AlternateContent') { + 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'); @@ -320,7 +333,7 @@ protected function readRunChild(XMLReader $xmlReader, \DOMElement $node, Abstrac /** * Read w:tbl. * - * @param \PhpOffice\Common\XMLReader $xmlReader + * @param \PhpOffice\PhpWord\Shared\XMLReader $xmlReader * @param \DOMElement $domNode * @param mixed $parent * @param string $docPart @@ -378,7 +391,7 @@ protected function readTable(XMLReader $xmlReader, \DOMElement $domNode, $parent /** * Read w:pPr. * - * @param \PhpOffice\Common\XMLReader $xmlReader + * @param \PhpOffice\PhpWord\Shared\XMLReader $xmlReader * @param \DOMElement $domNode * @return array|null */ @@ -413,7 +426,7 @@ protected function readParagraphStyle(XMLReader $xmlReader, \DOMElement $domNode /** * Read w:rPr * - * @param \PhpOffice\Common\XMLReader $xmlReader + * @param \PhpOffice\PhpWord\Shared\XMLReader $xmlReader * @param \DOMElement $domNode * @return array|null */ @@ -459,7 +472,7 @@ protected function readFontStyle(XMLReader $xmlReader, \DOMElement $domNode) /** * Read w:tblPr * - * @param \PhpOffice\Common\XMLReader $xmlReader + * @param \PhpOffice\PhpWord\Shared\XMLReader $xmlReader * @param \DOMElement $domNode * @return string|array|null * @todo Capture w:tblStylePr w:type="firstRow" @@ -509,7 +522,7 @@ protected function readTableStyle(XMLReader $xmlReader, \DOMElement $domNode) /** * Read w:tblpPr * - * @param \PhpOffice\Common\XMLReader $xmlReader + * @param \PhpOffice\PhpWord\Shared\XMLReader $xmlReader * @param \DOMElement $domNode * @return array */ @@ -534,7 +547,7 @@ private function readTablePosition(XMLReader $xmlReader, \DOMElement $domNode) /** * Read w:tblInd * - * @param \PhpOffice\Common\XMLReader $xmlReader + * @param \PhpOffice\PhpWord\Shared\XMLReader $xmlReader * @param \DOMElement $domNode * @return TblWidthComplexType */ @@ -552,7 +565,7 @@ private function readTableIndent(XMLReader $xmlReader, \DOMElement $domNode) /** * Read w:tcPr * - * @param \PhpOffice\Common\XMLReader $xmlReader + * @param \PhpOffice\PhpWord\Shared\XMLReader $xmlReader * @param \DOMElement $domNode * @return array */ @@ -573,11 +586,11 @@ private function readCellStyle(XMLReader $xmlReader, \DOMElement $domNode) * Returns the first child element found * * @param XMLReader $xmlReader - * @param \DOMElement $parentNode - * @param string|array $elements + * @param \DOMElement|null $parentNode + * @param string|array|null $elements * @return string|null */ - private function findPossibleElement(XMLReader $xmlReader, \DOMElement $parentNode = null, $elements) + private function findPossibleElement(XMLReader $xmlReader, \DOMElement $parentNode = null, $elements = null) { if (is_array($elements)) { //if element is an array, we take the first element that exists in the XML @@ -620,7 +633,7 @@ private function findPossibleAttribute(XMLReader $xmlReader, \DOMElement $node, /** * Read style definition * - * @param \PhpOffice\Common\XMLReader $xmlReader + * @param \PhpOffice\PhpWord\Shared\XMLReader $xmlReader * @param \DOMElement $parentNode * @param array $styleDefs * @ignoreScrutinizerPatch diff --git a/src/PhpWord/Reader/Word2007/DocPropsCore.php b/src/PhpWord/Reader/Word2007/DocPropsCore.php index 36eecebeae..d241df184a 100644 --- a/src/PhpWord/Reader/Word2007/DocPropsCore.php +++ b/src/PhpWord/Reader/Word2007/DocPropsCore.php @@ -17,8 +17,8 @@ namespace PhpOffice\PhpWord\Reader\Word2007; -use PhpOffice\Common\XMLReader; use PhpOffice\PhpWord\PhpWord; +use PhpOffice\PhpWord\Shared\XMLReader; /** * Core properties reader diff --git a/src/PhpWord/Reader/Word2007/DocPropsCustom.php b/src/PhpWord/Reader/Word2007/DocPropsCustom.php index a6835aacc1..feb41006c9 100644 --- a/src/PhpWord/Reader/Word2007/DocPropsCustom.php +++ b/src/PhpWord/Reader/Word2007/DocPropsCustom.php @@ -17,9 +17,9 @@ namespace PhpOffice\PhpWord\Reader\Word2007; -use PhpOffice\Common\XMLReader; use PhpOffice\PhpWord\Metadata\DocInfo; use PhpOffice\PhpWord\PhpWord; +use PhpOffice\PhpWord\Shared\XMLReader; /** * Custom properties reader diff --git a/src/PhpWord/Reader/Word2007/Document.php b/src/PhpWord/Reader/Word2007/Document.php index f0d1194a0b..13a92e4786 100644 --- a/src/PhpWord/Reader/Word2007/Document.php +++ b/src/PhpWord/Reader/Word2007/Document.php @@ -17,9 +17,9 @@ namespace PhpOffice\PhpWord\Reader\Word2007; -use PhpOffice\Common\XMLReader; use PhpOffice\PhpWord\Element\Section; use PhpOffice\PhpWord\PhpWord; +use PhpOffice\PhpWord\Shared\XMLReader; /** * Document reader @@ -97,7 +97,7 @@ private function readHeaderFooter($settings, Section &$section) /** * Read w:sectPr * - * @param \PhpOffice\Common\XMLReader $xmlReader + * @param \PhpOffice\PhpWord\Shared\XMLReader $xmlReader * @param \DOMElement $domNode * @ignoreScrutinizerPatch * @return array @@ -141,7 +141,7 @@ private function readSectionStyle(XMLReader $xmlReader, \DOMElement $domNode) /** * Read w:p node. * - * @param \PhpOffice\Common\XMLReader $xmlReader + * @param \PhpOffice\PhpWord\Shared\XMLReader $xmlReader * @param \DOMElement $node * @param \PhpOffice\PhpWord\Element\Section &$section * @@ -170,7 +170,7 @@ private function readWPNode(XMLReader $xmlReader, \DOMElement $node, Section &$s /** * Read w:sectPr node. * - * @param \PhpOffice\Common\XMLReader $xmlReader + * @param \PhpOffice\PhpWord\Shared\XMLReader $xmlReader * @param \DOMElement $node * @param \PhpOffice\PhpWord\Element\Section &$section */ diff --git a/src/PhpWord/Reader/Word2007/Footnotes.php b/src/PhpWord/Reader/Word2007/Footnotes.php index 634f473910..a8829d0bad 100644 --- a/src/PhpWord/Reader/Word2007/Footnotes.php +++ b/src/PhpWord/Reader/Word2007/Footnotes.php @@ -17,8 +17,8 @@ namespace PhpOffice\PhpWord\Reader\Word2007; -use PhpOffice\Common\XMLReader; use PhpOffice\PhpWord\PhpWord; +use PhpOffice\PhpWord\Shared\XMLReader; /** * Footnotes reader diff --git a/src/PhpWord/Reader/Word2007/Numbering.php b/src/PhpWord/Reader/Word2007/Numbering.php index 3f57cbf8be..dea8f3ee62 100644 --- a/src/PhpWord/Reader/Word2007/Numbering.php +++ b/src/PhpWord/Reader/Word2007/Numbering.php @@ -17,8 +17,8 @@ namespace PhpOffice\PhpWord\Reader\Word2007; -use PhpOffice\Common\XMLReader; use PhpOffice\PhpWord\PhpWord; +use PhpOffice\PhpWord\Shared\XMLReader; /** * Numbering reader @@ -89,7 +89,7 @@ public function read(PhpWord $phpWord) /** * Read numbering level definition from w:abstractNum and w:num * - * @param \PhpOffice\Common\XMLReader $xmlReader + * @param \PhpOffice\PhpWord\Shared\XMLReader $xmlReader * @param \DOMElement $subnode * @param int $levelId * @return array diff --git a/src/PhpWord/Reader/Word2007/Settings.php b/src/PhpWord/Reader/Word2007/Settings.php index 3084943b37..0a59e0454d 100644 --- a/src/PhpWord/Reader/Word2007/Settings.php +++ b/src/PhpWord/Reader/Word2007/Settings.php @@ -17,9 +17,9 @@ namespace PhpOffice\PhpWord\Reader\Word2007; -use PhpOffice\Common\XMLReader; use PhpOffice\PhpWord\ComplexType\TrackChangesView; use PhpOffice\PhpWord\PhpWord; +use PhpOffice\PhpWord\Shared\XMLReader; use PhpOffice\PhpWord\Style\Language; /** diff --git a/src/PhpWord/Reader/Word2007/Styles.php b/src/PhpWord/Reader/Word2007/Styles.php index 97f29b4316..37ce4909af 100644 --- a/src/PhpWord/Reader/Word2007/Styles.php +++ b/src/PhpWord/Reader/Word2007/Styles.php @@ -17,8 +17,8 @@ namespace PhpOffice\PhpWord\Reader\Word2007; -use PhpOffice\Common\XMLReader; use PhpOffice\PhpWord\PhpWord; +use PhpOffice\PhpWord\Shared\XMLReader; use PhpOffice\PhpWord\Style\Language; /** diff --git a/src/PhpWord/Settings.php b/src/PhpWord/Settings.php index 8de1a8df80..80e512d2a7 100644 --- a/src/PhpWord/Settings.php +++ b/src/PhpWord/Settings.php @@ -70,6 +70,7 @@ class Settings const DEFAULT_FONT_SIZE = 10; const DEFAULT_FONT_COLOR = '000000'; const DEFAULT_FONT_CONTENT_TYPE = 'default'; // default|eastAsia|cs + const DEFAULT_PAPER = 'A4'; /** * Compatibility option for XMLWriter @@ -119,6 +120,12 @@ class Settings */ private static $defaultFontSize = self::DEFAULT_FONT_SIZE; + /** + * Default paper + * @var string + */ + private static $defaultPaper = self::DEFAULT_PAPER; + /** * The user defined temporary directory. * @@ -432,6 +439,33 @@ public static function loadConfig($filename = null) return $config; } + /** + * Get default paper + * + * @return string + */ + public static function getDefaultPaper() + { + return self::$defaultPaper; + } + + /** + * Set default paper + * + * @param string $value + * @return bool + */ + public static function setDefaultPaper($value) + { + if (is_string($value) && trim($value) !== '') { + self::$defaultPaper = $value; + + return true; + } + + return false; + } + /** * Return the compatibility option used by the XMLWriter * diff --git a/src/PhpWord/Shared/Converter.php b/src/PhpWord/Shared/Converter.php index 39e8054543..05755ef796 100644 --- a/src/PhpWord/Shared/Converter.php +++ b/src/PhpWord/Shared/Converter.php @@ -338,9 +338,9 @@ public static function htmlToRgb($value) return false; } - $red = hexdec($red); - $green = hexdec($green); - $blue = hexdec($blue); + $red = ctype_xdigit($red) ? hexdec($red) : 0; + $green = ctype_xdigit($green) ? hexdec($green) : 0; + $blue = ctype_xdigit($blue) ? hexdec($blue) : 0; return array($red, $green, $blue); } diff --git a/src/PhpWord/Shared/Drawing.php b/src/PhpWord/Shared/Drawing.php new file mode 100644 index 0000000000..531ee24544 --- /dev/null +++ b/src/PhpWord/Shared/Drawing.php @@ -0,0 +1,248 @@ +preserveWhiteSpace = $preserveWhiteSpace; $dom->loadXML($html); @@ -80,7 +82,9 @@ public static function addHtml($element, $html, $fullHTML = false, $preserveWhit $node = $dom->getElementsByTagName('body'); self::parseNode($node->item(0), $element); - libxml_disable_entity_loader($orignalLibEntityLoader); + if (\PHP_VERSION_ID < 80000) { + libxml_disable_entity_loader($orignalLibEntityLoader); + } } /** @@ -178,7 +182,7 @@ protected static function parseNode($node, $element, $styles = array(), $data = } } $method = "parse{$method}"; - $newElement = call_user_func_array(array('PhpOffice\PhpWord\Shared\Html', $method), $arguments); + $newElement = call_user_func_array(array('PhpOffice\PhpWord\Shared\Html', $method), array_values($arguments)); // Retrieve back variables from arguments foreach ($keys as $key) { diff --git a/src/PhpWord/Shared/Microsoft/PasswordEncoder.php b/src/PhpWord/Shared/Microsoft/PasswordEncoder.php new file mode 100644 index 0000000000..fc0c7ecdf8 --- /dev/null +++ b/src/PhpWord/Shared/Microsoft/PasswordEncoder.php @@ -0,0 +1,235 @@ + array(1, 'md2'), + self::ALGORITHM_MD4 => array(2, 'md4'), + self::ALGORITHM_MD5 => array(3, 'md5'), + self::ALGORITHM_SHA_1 => array(4, 'sha1'), + self::ALGORITHM_MAC => array(5, ''), // 'mac' -> not possible with hash() + self::ALGORITHM_RIPEMD => array(6, 'ripemd'), + self::ALGORITHM_RIPEMD_160 => array(7, 'ripemd160'), + self::ALGORITHM_HMAC => array(9, ''), //'hmac' -> not possible with hash() + self::ALGORITHM_SHA_256 => array(12, 'sha256'), + self::ALGORITHM_SHA_384 => array(13, 'sha384'), + self::ALGORITHM_SHA_512 => array(14, 'sha512'), + ); + + private static $initialCodeArray = array( + 0xE1F0, + 0x1D0F, + 0xCC9C, + 0x84C0, + 0x110C, + 0x0E10, + 0xF1CE, + 0x313E, + 0x1872, + 0xE139, + 0xD40F, + 0x84F9, + 0x280C, + 0xA96A, + 0x4EC3, + ); + + private static $encryptionMatrix = array( + array(0xAEFC, 0x4DD9, 0x9BB2, 0x2745, 0x4E8A, 0x9D14, 0x2A09), + array(0x7B61, 0xF6C2, 0xFDA5, 0xEB6B, 0xC6F7, 0x9DCF, 0x2BBF), + array(0x4563, 0x8AC6, 0x05AD, 0x0B5A, 0x16B4, 0x2D68, 0x5AD0), + array(0x0375, 0x06EA, 0x0DD4, 0x1BA8, 0x3750, 0x6EA0, 0xDD40), + array(0xD849, 0xA0B3, 0x5147, 0xA28E, 0x553D, 0xAA7A, 0x44D5), + array(0x6F45, 0xDE8A, 0xAD35, 0x4A4B, 0x9496, 0x390D, 0x721A), + array(0xEB23, 0xC667, 0x9CEF, 0x29FF, 0x53FE, 0xA7FC, 0x5FD9), + array(0x47D3, 0x8FA6, 0x0F6D, 0x1EDA, 0x3DB4, 0x7B68, 0xF6D0), + array(0xB861, 0x60E3, 0xC1C6, 0x93AD, 0x377B, 0x6EF6, 0xDDEC), + array(0x45A0, 0x8B40, 0x06A1, 0x0D42, 0x1A84, 0x3508, 0x6A10), + array(0xAA51, 0x4483, 0x8906, 0x022D, 0x045A, 0x08B4, 0x1168), + array(0x76B4, 0xED68, 0xCAF1, 0x85C3, 0x1BA7, 0x374E, 0x6E9C), + array(0x3730, 0x6E60, 0xDCC0, 0xA9A1, 0x4363, 0x86C6, 0x1DAD), + array(0x3331, 0x6662, 0xCCC4, 0x89A9, 0x0373, 0x06E6, 0x0DCC), + array(0x1021, 0x2042, 0x4084, 0x8108, 0x1231, 0x2462, 0x48C4), + ); + + private static $passwordMaxLength = 15; + + /** + * Create a hashed password that MS Word will be able to work with + * @see https://blogs.msdn.microsoft.com/vsod/2010/04/05/how-to-set-the-editing-restrictions-in-word-using-open-xml-sdk-2-0/ + * + * @param string $password + * @param string $algorithmName + * @param string $salt + * @param int $spinCount + * @return string + */ + public static function hashPassword($password, $algorithmName = self::ALGORITHM_SHA_1, $salt = null, $spinCount = 10000) + { + $origEncoding = mb_internal_encoding(); + mb_internal_encoding('UTF-8'); + + $password = mb_substr($password, 0, min(self::$passwordMaxLength, mb_strlen($password))); + + // Get the single-byte values by iterating through the Unicode characters of the truncated password. + // For each character, if the low byte is not equal to 0, take it. Otherwise, take the high byte. + $passUtf8 = mb_convert_encoding($password, 'UCS-2LE', 'UTF-8'); + $byteChars = array(); + + for ($i = 0; $i < mb_strlen($password); $i++) { + $byteChars[$i] = ord(substr($passUtf8, $i * 2, 1)); + + if ($byteChars[$i] == 0) { + $byteChars[$i] = ord(substr($passUtf8, $i * 2 + 1, 1)); + } + } + + // build low-order word and hig-order word and combine them + $combinedKey = self::buildCombinedKey($byteChars); + // build reversed hexadecimal string + $hex = str_pad(strtoupper(dechex($combinedKey & 0xFFFFFFFF)), 8, '0', \STR_PAD_LEFT); + $reversedHex = $hex[6] . $hex[7] . $hex[4] . $hex[5] . $hex[2] . $hex[3] . $hex[0] . $hex[1]; + + $generatedKey = mb_convert_encoding($reversedHex, 'UCS-2LE', 'UTF-8'); + + // Implementation Notes List: + // Word requires that the initial hash of the password with the salt not be considered in the count. + // The initial hash of salt + key is not included in the iteration count. + $algorithm = self::getAlgorithm($algorithmName); + $generatedKey = hash($algorithm, $salt . $generatedKey, true); + + for ($i = 0; $i < $spinCount; $i++) { + $generatedKey = hash($algorithm, $generatedKey . pack('CCCC', $i, $i >> 8, $i >> 16, $i >> 24), true); + } + $generatedKey = base64_encode($generatedKey); + + mb_internal_encoding($origEncoding); + + return $generatedKey; + } + + /** + * Get algorithm from self::$algorithmMapping + * + * @param string $algorithmName + * @return string + */ + private static function getAlgorithm($algorithmName) + { + $algorithm = self::$algorithmMapping[$algorithmName][1]; + if ($algorithm == '') { + $algorithm = 'sha1'; + } + + return $algorithm; + } + + /** + * Returns the algorithm ID + * + * @param string $algorithmName + * @return int + */ + public static function getAlgorithmId($algorithmName) + { + return self::$algorithmMapping[$algorithmName][0]; + } + + /** + * Build combined key from low-order word and high-order word + * + * @param array $byteChars byte array representation of password + * @return int + */ + private static function buildCombinedKey($byteChars) + { + $byteCharsLength = count($byteChars); + // Compute the high-order word + // Initialize from the initial code array (see above), depending on the passwords length. + $highOrderWord = self::$initialCodeArray[$byteCharsLength - 1]; + + // For each character in the password: + // For every bit in the character, starting with the least significant and progressing to (but excluding) + // the most significant, if the bit is set, XOR the key’s high-order word with the corresponding word from + // the Encryption Matrix + for ($i = 0; $i < $byteCharsLength; $i++) { + $tmp = self::$passwordMaxLength - $byteCharsLength + $i; + $matrixRow = self::$encryptionMatrix[$tmp]; + for ($intBit = 0; $intBit < 7; $intBit++) { + if (($byteChars[$i] & (0x0001 << $intBit)) != 0) { + $highOrderWord = ($highOrderWord ^ $matrixRow[$intBit]); + } + } + } + + // Compute low-order word + // Initialize with 0 + $lowOrderWord = 0; + // For each character in the password, going backwards + for ($i = $byteCharsLength - 1; $i >= 0; $i--) { + // low-order word = (((low-order word SHR 14) AND 0x0001) OR (low-order word SHL 1) AND 0x7FFF)) XOR character + $lowOrderWord = (((($lowOrderWord >> 14) & 0x0001) | (($lowOrderWord << 1) & 0x7FFF)) ^ $byteChars[$i]); + } + // Lastly, low-order word = (((low-order word SHR 14) AND 0x0001) OR (low-order word SHL 1) AND 0x7FFF)) XOR strPassword length XOR 0xCE4B. + $lowOrderWord = (((($lowOrderWord >> 14) & 0x0001) | (($lowOrderWord << 1) & 0x7FFF)) ^ $byteCharsLength ^ 0xCE4B); + + // Combine the Low and High Order Word + return self::int32(($highOrderWord << 16) + $lowOrderWord); + } + + /** + * Simulate behaviour of (signed) int32 + * + * @codeCoverageIgnore + * @param int $value + * @return int + */ + private static function int32($value) + { + $value = ($value & 0xFFFFFFFF); + + if ($value & 0x80000000) { + $value = -((~$value & 0xFFFFFFFF) + 1); + } + + return $value; + } +} diff --git a/src/PhpWord/Shared/Text.php b/src/PhpWord/Shared/Text.php new file mode 100644 index 0000000000..c4a1ad620f --- /dev/null +++ b/src/PhpWord/Shared/Text.php @@ -0,0 +1,236 @@ +) + * 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 string $value + * @return string + */ + public static function toUTF8($value = '') + { + if (!is_null($value) && !self::isUTF8($value)) { + $value = utf8_encode($value); + } + + return $value; + } + + /** + * Returns unicode from UTF8 text + * + * The function is splitted to reduce cyclomatic complexity + * + * @param string $text UTF8 text + * @return string Unicode text + * @since 0.11.0 + */ + public static function toUnicode($text) + { + return self::unicodeToEntities(self::utf8ToUnicode($text)); + } + + /** + * Returns unicode array from UTF8 text + * + * @param string $text UTF8 text + * @return array + * @since 0.11.0 + * @see http://www.randomchaos.com/documents/?source=php_and_unicode + */ + public static function utf8ToUnicode($text) + { + $unicode = array(); + $values = array(); + $lookingFor = 1; + + // Gets unicode for each character + for ($i = 0; $i < strlen($text); $i++) { + $thisValue = ord($text[$i]); + if ($thisValue < 128) { + $unicode[] = $thisValue; + } else { + if (count($values) == 0) { + $lookingFor = $thisValue < 224 ? 2 : 3; + } + $values[] = $thisValue; + if (count($values) == $lookingFor) { + if ($lookingFor == 3) { + $number = (($values[0] % 16) * 4096) + (($values[1] % 64) * 64) + ($values[2] % 64); + } else { + $number = (($values[0] % 32) * 64) + ($values[1] % 64); + } + $unicode[] = $number; + $values = array(); + $lookingFor = 1; + } + } + } + + return $unicode; + } + + /** + * Returns entites from unicode array + * + * @param array $unicode + * @return string + * @since 0.11.0 + * @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 (!is_null($value)) { + if (substr($value, 0, 1) == '_') { + $value = substr($value, 1); + } + } + + return $value; + } +} diff --git a/src/PhpWord/Shared/XMLReader.php b/src/PhpWord/Shared/XMLReader.php new file mode 100644 index 0000000000..3905c52f19 --- /dev/null +++ b/src/PhpWord/Shared/XMLReader.php @@ -0,0 +1,216 @@ +open($zipFile); + $content = $zip->getFromName($xmlFile); + $zip->close(); + + if ($content === false) { + return false; + } + + return $this->getDomFromString($content); + } + + /** + * Get DOMDocument from content string + * + * @param string $content + * @return \DOMDocument + */ + public function getDomFromString($content) + { + 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 + * @param \DOMElement $contextNode + * @return \DOMNodeList + */ + public function getElements($path, \DOMElement $contextNode = null) + { + if ($this->dom === null) { + return array(); + } + if ($this->xpath === null) { + $this->xpath = new \DOMXpath($this->dom); + } + + if (is_null($contextNode)) { + return $this->xpath->query($path); + } + + return $this->xpath->query($path, $contextNode); + } + + /** + * Registers the namespace with the DOMXPath object + * + * @param string $prefix The prefix + * @param string $namespaceURI The URI of the namespace + * @throws \InvalidArgumentException If called before having loaded the DOM document + * @return bool true on success or false on failure + */ + public function registerNamespace($prefix, $namespaceURI) + { + if ($this->dom === null) { + throw new \InvalidArgumentException('Dom needs to be loaded before registering a namespace'); + } + if ($this->xpath === null) { + $this->xpath = new \DOMXpath($this->dom); + } + + return $this->xpath->registerNamespace($prefix, $namespaceURI); + } + + /** + * Get element + * + * @param string $path + * @param \DOMElement $contextNode + * @return \DOMElement|null + */ + public function getElement($path, \DOMElement $contextNode = null) + { + $elements = $this->getElements($path, $contextNode); + if ($elements->length > 0) { + return $elements->item(0); + } + + return null; + } + + /** + * Get element attribute + * + * @param string $attribute + * @param \DOMElement $contextNode + * @param string $path + * @return string|null + */ + public function getAttribute($attribute, \DOMElement $contextNode = null, $path = null) + { + $return = null; + if ($path !== null) { + $elements = $this->getElements($path, $contextNode); + if ($elements->length > 0) { + /** @var \DOMElement $node Type hint */ + $node = $elements->item(0); + $return = $node->getAttribute($attribute); + } + } else { + if ($contextNode !== null) { + $return = $contextNode->getAttribute($attribute); + } + } + + return ($return == '') ? null : $return; + } + + /** + * Get element value + * + * @param string $path + * @param \DOMElement $contextNode + * @return string|null + */ + public function getValue($path, \DOMElement $contextNode = null) + { + $elements = $this->getElements($path, $contextNode); + if ($elements->length > 0) { + return $elements->item(0)->nodeValue; + } + + return null; + } + + /** + * Count elements + * + * @param string $path + * @param \DOMElement $contextNode + * @return int + */ + public function countElements($path, \DOMElement $contextNode = null) + { + $elements = $this->getElements($path, $contextNode); + + return $elements->length; + } + + /** + * Element exists + * + * @param string $path + * @param \DOMElement $contextNode + * @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..930ad62ee1 --- /dev/null +++ b/src/PhpWord/Shared/XMLWriter.php @@ -0,0 +1,182 @@ +openMemory(); + } else { + if (!is_dir($pTemporaryStorageDir)) { + $pTemporaryStorageDir = sys_get_temp_dir(); + } + // Create temporary filename + $this->tempFileName = @tempnam($pTemporaryStorageDir, 'xml'); + + // Open storage + $this->openUri($this->tempFileName); + } + + if ($compatibility) { + $this->setIndent(false); + $this->setIndentString(''); + } else { + $this->setIndent(true); + $this->setIndentString(' '); + } + } + + /** + * Destructor + */ + public function __destruct() + { + // Unlink temporary files + if (empty($this->tempFileName)) { + return; + } + if (PHP_OS != 'WINNT' && @unlink($this->tempFileName) === false) { + throw new \Exception('The file ' . $this->tempFileName . ' could not be deleted.'); + } + } + + /** + * Get written data + * + * @return string + */ + public function getData() + { + if ($this->tempFileName == '') { + return $this->outputMemory(true); + } + + $this->flush(); + + return file_get_contents($this->tempFileName); + } + + /** + * Write simple element and attribute(s) block + * + * There are two options: + * 1. If the `$attributes` is an array, then it's an associative array of attributes + * 2. If not, then it's a simple attribute-value pair + * + * @param string $element + * @param string|array $attributes + * @param string $value + */ + public function writeElementBlock($element, $attributes, $value = null) + { + $this->startElement($element); + if (!is_array($attributes)) { + $attributes = array($attributes => $value); + } + foreach ($attributes as $attribute => $value) { + $this->writeAttribute($attribute, $value); + } + $this->endElement(); + } + + /** + * Write element if ... + * + * @param bool $condition + * @param string $element + * @param string $attribute + * @param mixed $value + */ + public function writeElementIf($condition, $element, $attribute = null, $value = null) + { + if ($condition == true) { + if (is_null($attribute)) { + $this->writeElement($element, $value); + } else { + $this->startElement($element); + $this->writeAttribute($attribute, $value); + $this->endElement(); + } + } + } + + /** + * Write attribute if ... + * + * @param bool $condition + * @param string $attribute + * @param mixed $value + */ + public function writeAttributeIf($condition, $attribute, $value) + { + if ($condition == true) { + $this->writeAttribute($attribute, $value); + } + } + + /** + * @param string $name + * @param mixed $value + * @return bool + */ + public function writeAttribute($name, $value) + { + if (is_float($value)) { + $value = json_encode($value); + } + + return parent::writeAttribute($name, $value); + } +} diff --git a/src/PhpWord/Style/AbstractStyle.php b/src/PhpWord/Style/AbstractStyle.php index 8edbe80bff..aca6635faa 100644 --- a/src/PhpWord/Style/AbstractStyle.php +++ b/src/PhpWord/Style/AbstractStyle.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWord\Style; -use PhpOffice\Common\Text; +use PhpOffice\PhpWord\Shared\Text; /** * Abstract style class diff --git a/src/PhpWord/Style/Paragraph.php b/src/PhpWord/Style/Paragraph.php index 72f0f8096c..522dea9baf 100644 --- a/src/PhpWord/Style/Paragraph.php +++ b/src/PhpWord/Style/Paragraph.php @@ -17,8 +17,8 @@ namespace PhpOffice\PhpWord\Style; -use PhpOffice\Common\Text; use PhpOffice\PhpWord\Exception\InvalidStyleException; +use PhpOffice\PhpWord\Shared\Text; use PhpOffice\PhpWord\SimpleType\Jc; use PhpOffice\PhpWord\SimpleType\TextAlignment; @@ -85,7 +85,7 @@ class Paragraph extends Border /** * Indentation * - * @var \PhpOffice\PhpWord\Style\Indentation + * @var \PhpOffice\PhpWord\Style\Indentation|null */ private $indentation; diff --git a/src/PhpWord/Style/Section.php b/src/PhpWord/Style/Section.php index ff9b0be09a..697add7456 100644 --- a/src/PhpWord/Style/Section.php +++ b/src/PhpWord/Style/Section.php @@ -17,6 +17,7 @@ namespace PhpOffice\PhpWord\Style; +use PhpOffice\PhpWord\Settings; use PhpOffice\PhpWord\SimpleType\VerticalJc; /** @@ -200,8 +201,11 @@ public function getPaperSize() * @param string $value * @return self */ - public function setPaperSize($value = 'A4') + public function setPaperSize($value = '') { + if (!$value) { + $value = Settings::getDefaultPaper(); + } if ($this->paper === null) { $this->paper = new Paper(); } diff --git a/src/PhpWord/TemplateProcessor.php b/src/PhpWord/TemplateProcessor.php index 7efc0f1ac8..fa8d8e6580 100644 --- a/src/PhpWord/TemplateProcessor.php +++ b/src/PhpWord/TemplateProcessor.php @@ -17,13 +17,13 @@ namespace PhpOffice\PhpWord; -use PhpOffice\Common\Text; -use PhpOffice\Common\XMLWriter; use PhpOffice\PhpWord\Escaper\RegExp; use PhpOffice\PhpWord\Escaper\Xml; use PhpOffice\PhpWord\Exception\CopyFileException; use PhpOffice\PhpWord\Exception\CreateTemporaryFileException; use PhpOffice\PhpWord\Exception\Exception; +use PhpOffice\PhpWord\Shared\Text; +use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Shared\ZipArchive; class TemplateProcessor @@ -170,7 +170,9 @@ protected function readPartWithRels($fileName) */ protected function transformSingleXml($xml, $xsltProcessor) { - $orignalLibEntityLoader = libxml_disable_entity_loader(true); + if (\PHP_VERSION_ID < 80000) { + $orignalLibEntityLoader = libxml_disable_entity_loader(true); + } $domDocument = new \DOMDocument(); if (false === $domDocument->loadXML($xml)) { throw new Exception('Could not load the given XML document.'); @@ -180,7 +182,9 @@ protected function transformSingleXml($xml, $xsltProcessor) if (false === $transformedXml) { throw new Exception('Could not transform the given XML document.'); } - libxml_disable_entity_loader($orignalLibEntityLoader); + if (\PHP_VERSION_ID < 80000) { + libxml_disable_entity_loader($orignalLibEntityLoader); + } return $transformedXml; } @@ -575,7 +579,7 @@ public function setImageValue($search, $replace, $limit = self::MAXIMUM_REPLACEM // define templates // result can be verified via "Open XML SDK 2.5 Productivity Tool" (http://www.microsoft.com/en-us/download/details.aspx?id=30425) - $imgTpl = ''; + $imgTpl = ''; foreach ($searchParts as $partFileName => &$partContent) { $partVariables = $this->getVariablesForPart($partContent); diff --git a/src/PhpWord/Writer/HTML/Element/AbstractElement.php b/src/PhpWord/Writer/HTML/Element/AbstractElement.php index dc5ccfaadc..30d1ccaa4c 100644 --- a/src/PhpWord/Writer/HTML/Element/AbstractElement.php +++ b/src/PhpWord/Writer/HTML/Element/AbstractElement.php @@ -17,9 +17,9 @@ namespace PhpOffice\PhpWord\Writer\HTML\Element; +use Laminas\Escaper\Escaper; use PhpOffice\PhpWord\Element\AbstractElement as Element; use PhpOffice\PhpWord\Writer\AbstractWriter; -use Zend\Escaper\Escaper; /** * Abstract HTML element writer @@ -50,7 +50,7 @@ abstract class AbstractElement protected $withoutP = false; /** - * @var \Zend\Escaper\Escaper|\PhpOffice\PhpWord\Escaper\AbstractEscaper + * @var \Laminas\Escaper\Escaper|\PhpOffice\PhpWord\Escaper\AbstractEscaper */ protected $escaper; diff --git a/src/PhpWord/Writer/HTML/Part/AbstractPart.php b/src/PhpWord/Writer/HTML/Part/AbstractPart.php index 2d86f399b0..97c763759a 100644 --- a/src/PhpWord/Writer/HTML/Part/AbstractPart.php +++ b/src/PhpWord/Writer/HTML/Part/AbstractPart.php @@ -17,9 +17,9 @@ namespace PhpOffice\PhpWord\Writer\HTML\Part; +use Laminas\Escaper\Escaper; use PhpOffice\PhpWord\Exception\Exception; use PhpOffice\PhpWord\Writer\AbstractWriter; -use Zend\Escaper\Escaper; /** * @since 0.11.0 @@ -32,7 +32,7 @@ abstract class AbstractPart private $parentWriter; /** - * @var \Zend\Escaper\Escaper + * @var \Laminas\Escaper\Escaper */ protected $escaper; diff --git a/src/PhpWord/Writer/ODText/Element/Field.php b/src/PhpWord/Writer/ODText/Element/Field.php new file mode 100644 index 0000000000..f7a74c1d66 --- /dev/null +++ b/src/PhpWord/Writer/ODText/Element/Field.php @@ -0,0 +1,81 @@ +getElement(); + if (!$element instanceof \PhpOffice\PhpWord\Element\Field) { + return; + } + + $type = strtolower($element->getType()); + switch ($type) { + case 'date': + case 'page': + case 'numpages': + $this->writeDefault($element, $type); + break; + } + } + + private function writeDefault(\PhpOffice\PhpWord\Element\Field $element, $type) + { + $xmlWriter = $this->getXmlWriter(); + + $xmlWriter->startElement('text:span'); + if (method_exists($element, 'getFontStyle')) { + $fstyle = $element->getFontStyle(); + if (is_string($fstyle)) { + $xmlWriter->writeAttribute('text:style-name', $fstyle); + } + } + switch ($type) { + case 'date': + $xmlWriter->startElement('text:date'); + $xmlWriter->writeAttribute('text:fixed', 'false'); + $xmlWriter->endElement(); + break; + case 'page': + $xmlWriter->startElement('text:page-number'); + $xmlWriter->writeAttribute('text:fixed', 'false'); + $xmlWriter->endElement(); + break; + case 'numpages': + $xmlWriter->startElement('text:page-count'); + $xmlWriter->endElement(); + break; + } + $xmlWriter->endElement(); // text:span + } +} diff --git a/src/PhpWord/Writer/ODText/Element/Image.php b/src/PhpWord/Writer/ODText/Element/Image.php index add45e1044..57aa546a4e 100644 --- a/src/PhpWord/Writer/ODText/Element/Image.php +++ b/src/PhpWord/Writer/ODText/Element/Image.php @@ -44,7 +44,7 @@ public function write() $height = Converter::pixelToCm($style->getHeight()); $xmlWriter->startElement('text:p'); - $xmlWriter->writeAttribute('text:style-name', 'Standard'); + $xmlWriter->writeAttribute('text:style-name', 'IM' . $mediaIndex); $xmlWriter->startElement('draw:frame'); $xmlWriter->writeAttribute('draw:style-name', 'fr' . $mediaIndex); diff --git a/src/PhpWord/Writer/ODText/Element/Link.php b/src/PhpWord/Writer/ODText/Element/Link.php index d6fec50777..23c9804b2d 100644 --- a/src/PhpWord/Writer/ODText/Element/Link.php +++ b/src/PhpWord/Writer/ODText/Element/Link.php @@ -41,7 +41,7 @@ public function write() $xmlWriter->startElement('text:a'); $xmlWriter->writeAttribute('xlink:type', 'simple'); - $xmlWriter->writeAttribute('xlink:href', $element->getSource()); + $xmlWriter->writeAttribute('xlink:href', ($element->isInternal() ? '#' : '') . $element->getSource()); $this->writeText($element->getText()); $xmlWriter->endElement(); // text:a diff --git a/src/PhpWord/Writer/ODText/Element/PageBreak.php b/src/PhpWord/Writer/ODText/Element/PageBreak.php index ecf4760740..8e4f46950c 100644 --- a/src/PhpWord/Writer/ODText/Element/PageBreak.php +++ b/src/PhpWord/Writer/ODText/Element/PageBreak.php @@ -30,7 +30,7 @@ public function write() $xmlWriter = $this->getXmlWriter(); $xmlWriter->startElement('text:p'); - $xmlWriter->writeAttribute('text:style-name', 'P1'); + $xmlWriter->writeAttribute('text:style-name', 'PB'); $xmlWriter->endElement(); } } diff --git a/src/PhpWord/Writer/ODText/Element/Table.php b/src/PhpWord/Writer/ODText/Element/Table.php index 088330ae5f..adcf8ab4e3 100644 --- a/src/PhpWord/Writer/ODText/Element/Table.php +++ b/src/PhpWord/Writer/ODText/Element/Table.php @@ -17,9 +17,9 @@ namespace PhpOffice\PhpWord\Writer\ODText\Element; -use PhpOffice\Common\XMLWriter; use PhpOffice\PhpWord\Element\Row as RowElement; use PhpOffice\PhpWord\Element\Table as TableElement; +use PhpOffice\PhpWord\Shared\XMLWriter; /** * Table element writer @@ -60,7 +60,7 @@ public function write() /** * Write column. * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Element\Table $element */ private function writeColumns(XMLWriter $xmlWriter, TableElement $element) @@ -77,7 +77,7 @@ private function writeColumns(XMLWriter $xmlWriter, TableElement $element) /** * Write row. * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Element\Row $row */ private function writeRow(XMLWriter $xmlWriter, RowElement $row) diff --git a/src/PhpWord/Writer/ODText/Element/Text.php b/src/PhpWord/Writer/ODText/Element/Text.php index 7dcd28a013..464d277739 100644 --- a/src/PhpWord/Writer/ODText/Element/Text.php +++ b/src/PhpWord/Writer/ODText/Element/Text.php @@ -42,12 +42,12 @@ public function write() // @todo Commented for TextRun. Should really checkout this value // $fStyleIsObject = ($fontStyle instanceof Font) ? true : false; - $fStyleIsObject = false; + //$fStyleIsObject = false; - if ($fStyleIsObject) { - // Don't never be the case, because I browse all sections for cleaning all styles not declared - throw new Exception('PhpWord : $fStyleIsObject wouldn\'t be an object'); - } + //if ($fStyleIsObject) { + // Don't never be the case, because I browse all sections for cleaning all styles not declared + // throw new Exception('PhpWord : $fStyleIsObject wouldn\'t be an object'); + //} if (!$this->withoutP) { $xmlWriter->startElement('text:p'); // text:p @@ -59,18 +59,26 @@ public function write() } else { if (empty($fontStyle)) { if (empty($paragraphStyle)) { - $xmlWriter->writeAttribute('text:style-name', 'P1'); + if (!$this->withoutP) { + $xmlWriter->writeAttribute('text:style-name', 'Normal'); + } } elseif (is_string($paragraphStyle)) { - $xmlWriter->writeAttribute('text:style-name', $paragraphStyle); + if (!$this->withoutP) { + $xmlWriter->writeAttribute('text:style-name', $paragraphStyle); + } } $this->writeChangeInsertion(true, $element->getTrackChange()); - $this->writeText($element->getText()); + $this->replaceTabs($element->getText(), $xmlWriter); $this->writeChangeInsertion(false, $element->getTrackChange()); } else { if (empty($paragraphStyle)) { - $xmlWriter->writeAttribute('text:style-name', 'Standard'); + if (!$this->withoutP) { + $xmlWriter->writeAttribute('text:style-name', 'Normal'); + } } elseif (is_string($paragraphStyle)) { - $xmlWriter->writeAttribute('text:style-name', $paragraphStyle); + if (!$this->withoutP) { + $xmlWriter->writeAttribute('text:style-name', $paragraphStyle); + } } // text:span $xmlWriter->startElement('text:span'); @@ -78,7 +86,7 @@ public function write() $xmlWriter->writeAttribute('text:style-name', $fontStyle); } $this->writeChangeInsertion(true, $element->getTrackChange()); - $this->writeText($element->getText()); + $this->replaceTabs($element->getText(), $xmlWriter); $this->writeChangeInsertion(false, $element->getTrackChange()); $xmlWriter->endElement(); } @@ -88,6 +96,34 @@ public function write() } } + private function replacetabs($text, $xmlWriter) + { + if (preg_match('/^ +/', $text, $matches)) { + $num = strlen($matches[0]); + $xmlWriter->startElement('text:s'); + $xmlWriter->writeAttributeIf($num > 1, 'text:c', "$num"); + $xmlWriter->endElement(); + $text = preg_replace('/^ +/', '', $text); + } + preg_match_all('/([\\s\\S]*?)(\\t| +| ?$)/', $text, $matches, PREG_SET_ORDER); + foreach ($matches as $match) { + $this->writeText($match[1]); + if ($match[2] === '') { + break; + } elseif ($match[2] === "\t") { + $xmlWriter->writeElement('text:tab'); + } elseif ($match[2] === ' ') { + $xmlWriter->writeElement('text:s'); + break; + } else { + $num = strlen($match[2]); + $xmlWriter->startElement('text:s'); + $xmlWriter->writeAttributeIf($num > 1, 'text:c', "$num"); + $xmlWriter->endElement(); + } + } + } + private function writeChangeInsertion($start = true, TrackChange $trackChange = null) { if ($trackChange == null || $trackChange->getChangeType() != TrackChange::INSERTED) { diff --git a/src/PhpWord/Writer/ODText/Element/TextRun.php b/src/PhpWord/Writer/ODText/Element/TextRun.php index 78e5a8adae..9a00577302 100644 --- a/src/PhpWord/Writer/ODText/Element/TextRun.php +++ b/src/PhpWord/Writer/ODText/Element/TextRun.php @@ -22,7 +22,7 @@ * * @since 0.10.0 */ -class TextRun extends AbstractElement +class TextRun extends Text { /** * Write element @@ -33,6 +33,12 @@ public function write() $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..98ddbbf445 100644 --- a/src/PhpWord/Writer/ODText/Element/Title.php +++ b/src/PhpWord/Writer/ODText/Element/Title.php @@ -36,7 +36,22 @@ 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); @@ -44,6 +59,21 @@ public function write() $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..4a7ace78ca 100644 --- a/src/PhpWord/Writer/ODText/Part/AbstractPart.php +++ b/src/PhpWord/Writer/ODText/Part/AbstractPart.php @@ -17,8 +17,8 @@ namespace PhpOffice\PhpWord\Writer\ODText\Part; -use PhpOffice\Common\XMLWriter; use PhpOffice\PhpWord\Settings; +use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Style; use PhpOffice\PhpWord\Style\Font; use PhpOffice\PhpWord\Writer\Word2007\Part\AbstractPart as Word2007AbstractPart; @@ -36,7 +36,7 @@ abstract class AbstractPart extends Word2007AbstractPart /** * Write common root attributes. * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter */ protected function writeCommonRootAttributes(XMLWriter $xmlWriter) { @@ -72,7 +72,7 @@ protected function writeCommonRootAttributes(XMLWriter $xmlWriter) /** * Write font faces declaration. * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter */ protected function writeFontFaces(XMLWriter $xmlWriter) { diff --git a/src/PhpWord/Writer/ODText/Part/Content.php b/src/PhpWord/Writer/ODText/Part/Content.php index 99ee93536e..b6a1c95e65 100644 --- a/src/PhpWord/Writer/ODText/Part/Content.php +++ b/src/PhpWord/Writer/ODText/Part/Content.php @@ -17,14 +17,15 @@ namespace PhpOffice\PhpWord\Writer\ODText\Part; -use PhpOffice\Common\XMLWriter; use PhpOffice\PhpWord\Element\AbstractContainer; +use PhpOffice\PhpWord\Element\Field; use PhpOffice\PhpWord\Element\Image; use PhpOffice\PhpWord\Element\Table; use PhpOffice\PhpWord\Element\Text; use PhpOffice\PhpWord\Element\TextRun; use PhpOffice\PhpWord\Element\TrackChange; use PhpOffice\PhpWord\PhpWord; +use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Style; use PhpOffice\PhpWord\Style\Font; use PhpOffice\PhpWord\Style\Paragraph; @@ -46,6 +47,7 @@ class Content extends AbstractPart * @var array */ private $autoStyles = array('Section' => array(), 'Image' => array(), 'Table' => array()); + private $imageParagraphStyles = array(); /** * Write part @@ -128,6 +130,9 @@ public function write() $xmlWriter->startElement('text:section'); $xmlWriter->writeAttribute('text:name', $name); $xmlWriter->writeAttribute('text:style-name', $name); + $xmlWriter->startElement('text:p'); + $xmlWriter->writeAttribute('text:style-name', 'SB' . $section->getSectionId()); + $xmlWriter->endElement(); $containerWriter = new Container($xmlWriter, $section); $containerWriter->write(); $xmlWriter->endElement(); // text:section @@ -146,7 +151,7 @@ public function write() * * @since 0.11.0 * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter */ private function writeAutoStyles(XMLWriter $xmlWriter) { @@ -168,34 +173,65 @@ private function writeAutoStyles(XMLWriter $xmlWriter) /** * Write automatic styles. * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter */ private function writeTextStyles(XMLWriter $xmlWriter) { $styles = Style::getStyles(); $paragraphStyleCount = 0; - if (count($styles) > 0) { - foreach ($styles as $style) { - if ($style->isAuto() === true) { - $styleClass = str_replace('\\Style\\', '\\Writer\\ODText\\Style\\', get_class($style)); - if (class_exists($styleClass)) { - /** @var \PhpOffice\PhpWord\Writer\ODText\Style\AbstractStyle $styleWriter Type hint */ - $styleWriter = new $styleClass($xmlWriter, $style); - $styleWriter->write(); - } - if ($style instanceof Paragraph) { - $paragraphStyleCount++; - } - } - } - if ($paragraphStyleCount == 0) { + + $style = new Paragraph(); + $style->setStyleName('PB'); + $style->setAuto(); + $styleWriter = new ParagraphStyleWriter($xmlWriter, $style); + $styleWriter->write(); + + $sects = $this->getParentWriter()->getPhpWord()->getSections(); + $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 = $style->getStyleName(); + if (substr($sty, 0, 8) === 'Heading_') { $style = new Paragraph(); - $style->setStyleName('P1'); + $style->setStyleName('HD' . substr($sty, 8)); + $style->setAuto(); + $styleWriter = new ParagraphStyleWriter($xmlWriter, $style); + $styleWriter->write(); + $style = new Paragraph(); + $style->setStyleName('HE' . substr($sty, 8)); $style->setAuto(); $styleWriter = new ParagraphStyleWriter($xmlWriter, $style); $styleWriter->write(); } } + + foreach ($styles as $style) { + if ($style->isAuto() === true) { + $styleClass = str_replace('\\Style\\', '\\Writer\\ODText\\Style\\', get_class($style)); + if (class_exists($styleClass)) { + /** @var \PhpOffice\PhpWord\Writer\ODText\Style\AbstractStyle $styleWriter Type hint */ + $styleWriter = new $styleClass($xmlWriter, $style); + $styleWriter->write(); + } + if ($style instanceof Paragraph) { + $paragraphStyleCount++; + } + } + } + foreach ($this->imageParagraphStyles as $style) { + $styleWriter = new \PhpOffice\PhpWord\Writer\ODText\Style\Paragraph($xmlWriter, $style); + $styleWriter->write(); + } } /** @@ -231,20 +267,29 @@ private function getContainerStyle($container, &$paragraphStyleCount, &$fontStyl $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 \PhpOffice\PhpWord\Style\Paragraph(); + $sty->setStyleName('IM' . $element->getMediaIndex()); + $sty->setAuto(); + $sty->setAlignment($style->getAlignment()); + $this->imageParagraphStyles[] = $sty; } elseif ($element instanceof Table) { /** @var \PhpOffice\PhpWord\Style\Table $style */ $style = $element->getStyle(); + if (is_string($style)) { + $style = Style::getStyle($style); + } if ($style === null) { $style = new TableStyle(); - } elseif (is_string($style)) { - $style = Style::getStyle($style); } $style->setStyleName($element->getElementId()); $style->setColumnWidths($element->findFirstDefinedCellWidths()); @@ -260,7 +305,7 @@ private function getContainerStyle($container, &$paragraphStyleCount, &$fontStyl * @param int $paragraphStyleCount * @param int $fontStyleCount */ - private function getElementStyle(&$element, &$paragraphStyleCount, &$fontStyleCount) + private function getElementStyle($element, &$paragraphStyleCount, &$fontStyleCount) { $fontStyle = $element->getFontStyle(); $paragraphStyle = $element->getParagraphStyle(); @@ -268,16 +313,91 @@ 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 \PhpOffice\PhpWord\Element\Field $element + * @param int $paragraphStyleCount + * @param int $fontStyleCount + */ + private function getElementStyleField($element, &$fontStyleCount) + { + $fontStyle = $element->getFontStyle(); + $phpWord = $this->getParentWriter()->getPhpWord(); + + if ($fontStyle instanceof Font) { + $name = $fontStyle->getStyleName(); + if (!$name) { + $fontStyleCount++; + $style = $phpWord->addFontStyle("T{$fontStyleCount}", $fontStyle, null); + $style->setAuto(); + $style->setParagraph(null); + $element->setFontStyle("T{$fontStyleCount}"); + } else { + $element->setFontStyle($name); + } + } + } + + /** + * Get style of individual element + * + * @param \PhpOffice\PhpWord\Element\TextRun $element + * @param int $paragraphStyleCount + */ + private function getElementStyleTextRun($element, &$paragraphStyleCount) + { + $paragraphStyle = $element->getParagraphStyle(); + $phpWord = $this->getParentWriter()->getPhpWord(); + + if ($paragraphStyle instanceof Paragraph) { // Paragraph + $name = $paragraphStyle->getStyleName(); + if (!$name) { + $paragraphStyleCount++; + $style = $phpWord->addParagraphStyle("P{$paragraphStyleCount}", $paragraphStyle); + $style->setAuto(); + $element->setParagraphStyle("P{$paragraphStyleCount}"); + } else { + $element->setParagraphStyle($name); + } + } elseif ($paragraphStyle) { $paragraphStyleCount++; - $style = $phpWord->addParagraphStyle("P{$paragraphStyleCount}", array()); + $parstylename = "P$paragraphStyleCount" . "_$paragraphStyle"; + $style = $phpWord->addParagraphStyle($parstylename, $paragraphStyle); $style->setAuto(); - $element->setParagraphStyle("P{$paragraphStyleCount}"); + $element->setParagraphStyle($parstylename); } } diff --git a/src/PhpWord/Writer/ODText/Part/Meta.php b/src/PhpWord/Writer/ODText/Part/Meta.php index f38ad01d56..8f3f1fb969 100644 --- a/src/PhpWord/Writer/ODText/Part/Meta.php +++ b/src/PhpWord/Writer/ODText/Part/Meta.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWord\Writer\ODText\Part; -use PhpOffice\Common\XMLWriter; +use PhpOffice\PhpWord\Shared\XMLWriter; /** * ODText meta part writer: meta.xml @@ -86,7 +86,7 @@ public function write() /** * Write individual property * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param string $property * @param string $value * diff --git a/src/PhpWord/Writer/ODText/Part/Styles.php b/src/PhpWord/Writer/ODText/Part/Styles.php index e7635e9854..befd23a2ac 100644 --- a/src/PhpWord/Writer/ODText/Part/Styles.php +++ b/src/PhpWord/Writer/ODText/Part/Styles.php @@ -17,8 +17,9 @@ namespace PhpOffice\PhpWord\Writer\ODText\Part; -use PhpOffice\Common\XMLWriter; use PhpOffice\PhpWord\Settings; +use PhpOffice\PhpWord\Shared\Converter; +use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Style; /** @@ -65,7 +66,7 @@ public function write() /** * Write default styles. * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter */ private function writeDefault(XMLWriter $xmlWriter) { @@ -86,6 +87,9 @@ private function writeDefault(XMLWriter $xmlWriter) $latinLang = $language != null && is_string($language->getLatin()) ? explode('-', $language->getLatin()) : array('fr', 'FR'); $asianLang = $language != null && is_string($language->getEastAsia()) ? explode('-', $language->getEastAsia()) : array('zh', 'CN'); $complexLang = $language != null && is_string($language->getBidirectional()) ? explode('-', $language->getBidirectional()) : array('hi', 'IN'); + if ($this->getParentWriter()->getPhpWord()->getSettings()->hasHideGrammaticalErrors()) { + $latinLang = $asianLang = $complexLang = array('zxx', 'none'); + } // Font $xmlWriter->startElement('style:text-properties'); @@ -114,7 +118,7 @@ private function writeDefault(XMLWriter $xmlWriter) /** * Write named styles. * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter */ private function writeNamed(XMLWriter $xmlWriter) { @@ -134,24 +138,74 @@ private function writeNamed(XMLWriter $xmlWriter) } /** - * Write page layout styles. + * Convert int in twips to inches/cm then to string and append unit * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param int|float $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 + * + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter */ private function writePageLayout(XMLWriter $xmlWriter) { + $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\PhpWord\Shared\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Element\Section $section + * @param int $sectionNbr + */ + private function writePageLayoutIndiv(XMLWriter $xmlWriter, $section, $sectionNbr) + { + $sty = $section->getStyle(); + if (count($section->getHeaders()) > 0) { + $topfactor = 0.5; + } else { + $topfactor = 1.0; + } + if (count($section->getFooters()) > 0) { + $botfactor = 0.5; + } else { + $botfactor = 1.0; + } + $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 +230,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 @@ -187,17 +255,50 @@ private function writePageLayout(XMLWriter $xmlWriter) /** * Write master style. * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter */ private function writeMaster(XMLWriter $xmlWriter) { $xmlWriter->startElement('office:master-styles'); - $xmlWriter->startElement('style:master-page'); - $xmlWriter->writeAttribute('style:name', 'Standard'); - $xmlWriter->writeAttribute('style:page-layout-name', 'Mpm1'); - $xmlWriter->endElement(); // style:master-page - + $sections = $this->getParentWriter()->getPhpWord()->getSections(); + $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/Font.php b/src/PhpWord/Writer/ODText/Style/Font.php index 29657c5af2..ae9c417e9d 100644 --- a/src/PhpWord/Writer/ODText/Style/Font.php +++ b/src/PhpWord/Writer/ODText/Style/Font.php @@ -35,6 +35,14 @@ public function write() } $xmlWriter = $this->getXmlWriter(); + $stylep = (method_exists($style, 'getParagraph')) ? $style->getParagraph() : null; + if ($stylep instanceof \PhpOffice\PhpWord\Style\Paragraph) { + $temp1 = clone $stylep; + $temp1->setStyleName($style->getStyleName()); + $temp2 = new \PhpOffice\PhpWord\Writer\ODText\Style\Paragraph($xmlWriter, $temp1); + $temp2->write(); + } + $xmlWriter->startElement('style:style'); $xmlWriter->writeAttribute('style:name', $style->getStyleName()); $xmlWriter->writeAttribute('style:family', 'text'); @@ -53,7 +61,7 @@ public function write() // Color $color = $style->getColor(); - $xmlWriter->writeAttributeIf($color != '', 'fo:color', '#' . $color); + $xmlWriter->writeAttributeIf($color != '', 'fo:color', '#' . \PhpOffice\PhpWord\Shared\Converter::stringToRgb($color)); // Bold & italic $xmlWriter->writeAttributeIf($style->isBold(), 'fo:font-weight', 'bold'); @@ -82,6 +90,15 @@ public function write() $xmlWriter->writeAttributeIf($style->isSuperScript(), 'style:text-position', 'super'); $xmlWriter->writeAttributeIf($style->isSubScript(), 'style:text-position', 'sub'); + if ($style->isNoProof()) { + $xmlWriter->writeAttribute('fo:language', 'zxx'); + $xmlWriter->writeAttribute('style:language-asian', 'zxx'); + $xmlWriter->writeAttribute('style:language-complex', 'zxx'); + $xmlWriter->writeAttribute('fo:country', 'none'); + $xmlWriter->writeAttribute('style:country-asian', 'none'); + $xmlWriter->writeAttribute('style:country-complex', 'none'); + } + // @todo Foreground-Color // @todo Background color diff --git a/src/PhpWord/Writer/ODText/Style/Paragraph.php b/src/PhpWord/Writer/ODText/Style/Paragraph.php index f247dcc11c..9d38de86c5 100644 --- a/src/PhpWord/Writer/ODText/Style/Paragraph.php +++ b/src/PhpWord/Writer/ODText/Style/Paragraph.php @@ -17,6 +17,8 @@ namespace PhpOffice\PhpWord\Writer\ODText\Style; +use PhpOffice\PhpWord\Shared\Converter; + /** * Font style writer * @@ -35,31 +37,119 @@ public function write() } $xmlWriter = $this->getXmlWriter(); - $marginTop = (is_null($style->getSpaceBefore()) || $style->getSpaceBefore() == 0) ? '0' : round(17.6 / $style->getSpaceBefore(), 2); - $marginBottom = (is_null($style->getSpaceAfter()) || $style->getSpaceAfter() == 0) ? '0' : round(17.6 / $style->getSpaceAfter(), 2); + $marginTop = $style->getSpaceBefore(); + $marginBottom = $style->getSpaceAfter(); $xmlWriter->startElement('style:style'); + + $styleName = $style->getStyleName(); + $styleAuto = false; + $mpm = ''; + $psm = ''; + $pagestart = -1; + $breakafter = $breakbefore = $breakauto = false; + if ($style->isAuto()) { + if (substr($styleName, 0, 2) === 'PB') { + $styleAuto = true; + $breakafter = true; + } elseif (substr($styleName, 0, 2) === 'SB') { + $styleAuto = true; + $mpm = 'Standard' . substr($styleName, 2); + $psn = $style->getNumLevel(); + $pagestart = $psn; + } elseif (substr($styleName, 0, 2) === 'HD') { + $styleAuto = true; + $psm = 'Heading_' . substr($styleName, 2); + $stylep = \PhpOffice\PhpWord\Style::getStyle($psm); + if ($stylep instanceof \PhpOffice\PhpWord\Style\Font) { + if (method_exists($stylep, 'getParagraph')) { + $stylep = $stylep->getParagraph(); + } + } + if ($stylep instanceof \PhpOffice\PhpWord\Style\Paragraph) { + if ($stylep->hasPageBreakBefore()) { + $breakbefore = true; + } + } + } elseif (substr($styleName, 0, 2) === 'HE') { + $styleAuto = true; + $psm = 'Heading_' . substr($styleName, 2); + $breakauto = true; + } else { + $styleAuto = true; + $psm = 'Normal'; + if (preg_match('/^P\\d+_(\\w+)$/', $styleName, $matches)) { + $psm = $matches[1]; + } + } + } + $xmlWriter->writeAttribute('style:name', $style->getStyleName()); $xmlWriter->writeAttribute('style:family', 'paragraph'); - if ($style->isAuto()) { - $xmlWriter->writeAttribute('style:parent-style-name', 'Standard'); - $xmlWriter->writeAttribute('style:master-page-name', 'Standard'); + if ($styleAuto) { + $xmlWriter->writeAttributeIf($psm !== '', 'style:parent-style-name', $psm); + $xmlWriter->writeAttributeIf($mpm !== '', 'style:master-page-name', $mpm); } $xmlWriter->startElement('style:paragraph-properties'); - if ($style->isAuto()) { - $xmlWriter->writeAttribute('style:page-number', 'auto'); - } else { - $xmlWriter->writeAttribute('fo:margin-top', $marginTop . 'cm'); - $xmlWriter->writeAttribute('fo:margin-bottom', $marginBottom . 'cm'); - $xmlWriter->writeAttribute('fo:text-align', $style->getAlignment()); + if ($styleAuto) { + if ($breakafter) { + $xmlWriter->writeAttribute('fo:break-after', 'page'); + $xmlWriter->writeAttribute('fo:margin-top', '0cm'); + $xmlWriter->writeAttribute('fo:margin-bottom', '0cm'); + } elseif ($breakbefore) { + $xmlWriter->writeAttribute('fo:break-before', 'page'); + } elseif ($breakauto) { + $xmlWriter->writeAttribute('fo:break-before', 'auto'); + } + if ($pagestart > 0) { + $xmlWriter->writeAttribute('style:page-number', $pagestart); + } + } + if (!$breakafter && !$breakbefore && !$breakauto) { + $twipToPoint = Converter::INCH_TO_TWIP / Converter::INCH_TO_POINT; // 20 + $xmlWriter->writeAttributeIf($marginTop !== null, 'fo:margin-top', ($marginTop / $twipToPoint) . 'pt'); + $xmlWriter->writeAttributeIf($marginBottom !== null, 'fo:margin-bottom', ($marginBottom / $twipToPoint) . 'pt'); + } + $temp = $style->getAlignment(); + $xmlWriter->writeAttributeIf($temp !== '', 'fo:text-align', $temp); + $temp = $style->getLineHeight(); + $xmlWriter->writeAttributeIf($temp !== null, 'fo:line-height', ((string) ($temp * 100) . '%')); + $xmlWriter->writeAttributeIf($style->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/PDF/DomPDF.php b/src/PhpWord/Writer/PDF/DomPDF.php index 5fa8f75dbb..53eea81588 100644 --- a/src/PhpWord/Writer/PDF/DomPDF.php +++ b/src/PhpWord/Writer/PDF/DomPDF.php @@ -35,6 +35,16 @@ class DomPDF extends AbstractRenderer implements WriterInterface */ protected $includeFile = null; + /** + * Gets the implementation of external PDF library that should be used. + * + * @return Dompdf implementation + */ + protected function createExternalWriterInstance() + { + return new DompdfLib(); + } + /** * Save PhpWord to file. * @@ -49,7 +59,7 @@ public function save($filename = null) $orientation = 'portrait'; // Create PDF - $pdf = new DompdfLib(); + $pdf = $this->createExternalWriterInstance(); $pdf->setPaper(strtolower($paperSize), $orientation); $pdf->loadHtml(str_replace(PHP_EOL, '', $this->getContent())); $pdf->render(); diff --git a/src/PhpWord/Writer/PDF/MPDF.php b/src/PhpWord/Writer/PDF/MPDF.php index e63f5dfd68..464f156ce5 100644 --- a/src/PhpWord/Writer/PDF/MPDF.php +++ b/src/PhpWord/Writer/PDF/MPDF.php @@ -44,6 +44,18 @@ public function __construct(PhpWord $phpWord) parent::__construct($phpWord); } + /** + * Gets the implementation of external PDF library that should be used. + * + * @return Mpdf implementation + */ + protected function createExternalWriterInstance() + { + $mPdfClass = $this->getMPdfClassName(); + + return new $mPdfClass(); + } + /** * Save PhpWord to file. * @@ -58,8 +70,7 @@ public function save($filename = null) $orientation = strtoupper('portrait'); // Create PDF - $mPdfClass = $this->getMPdfClassName(); - $pdf = new $mPdfClass(); + $pdf = $this->createExternalWriterInstance(); $pdf->_setPageSize($paperSize, $orientation); $pdf->addPage($orientation); diff --git a/src/PhpWord/Writer/PDF/TCPDF.php b/src/PhpWord/Writer/PDF/TCPDF.php index badab0460e..3abbbf069d 100644 --- a/src/PhpWord/Writer/PDF/TCPDF.php +++ b/src/PhpWord/Writer/PDF/TCPDF.php @@ -36,6 +36,20 @@ class TCPDF extends AbstractRenderer implements WriterInterface */ protected $includeFile = 'tcpdf.php'; + /** + * Gets the implementation of external PDF library that should be used. + * + * @param string $orientation Page orientation + * @param string $unit Unit measure + * @param string $paperSize Paper size + * + * @return \TCPDF implementation + */ + protected function createExternalWriterInstance($orientation, $unit, $paperSize) + { + return new \TCPDF($orientation, $unit, $paperSize); + } + /** * Save PhpWord to file. * @@ -50,7 +64,7 @@ public function save($filename = null) $orientation = 'P'; // Create PDF - $pdf = new \TCPDF($orientation, 'pt', $paperSize); + $pdf = $this->createExternalWriterInstance($orientation, 'pt', $paperSize); $pdf->setFontSubsetting(false); $pdf->setPrintHeader(false); $pdf->setPrintFooter(false); diff --git a/src/PhpWord/Writer/RTF/Element/AbstractElement.php b/src/PhpWord/Writer/RTF/Element/AbstractElement.php index 132890e6ec..fa1058bdb0 100644 --- a/src/PhpWord/Writer/RTF/Element/AbstractElement.php +++ b/src/PhpWord/Writer/RTF/Element/AbstractElement.php @@ -17,10 +17,10 @@ namespace PhpOffice\PhpWord\Writer\RTF\Element; -use PhpOffice\Common\Text as CommonText; use PhpOffice\PhpWord\Element\AbstractElement as Element; use PhpOffice\PhpWord\Escaper\Rtf; use PhpOffice\PhpWord\Settings; +use PhpOffice\PhpWord\Shared\Text as SharedText; use PhpOffice\PhpWord\Style; use PhpOffice\PhpWord\Style\Font as FontStyle; use PhpOffice\PhpWord\Style\Paragraph as ParagraphStyle; @@ -126,7 +126,7 @@ protected function writeText($text) return $this->escaper->escape($text); } - return CommonText::toUnicode($text); // todo: replace with `return $text;` later. + return SharedText::toUnicode($text); // todo: replace with `return $text;` later. } /** diff --git a/src/PhpWord/Writer/Word2007/Element/AbstractElement.php b/src/PhpWord/Writer/Word2007/Element/AbstractElement.php index 63f45a761f..ee0fb2f901 100644 --- a/src/PhpWord/Writer/Word2007/Element/AbstractElement.php +++ b/src/PhpWord/Writer/Word2007/Element/AbstractElement.php @@ -17,10 +17,10 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Element; -use PhpOffice\Common\Text as CommonText; -use PhpOffice\Common\XMLWriter; use PhpOffice\PhpWord\Element\AbstractElement as Element; use PhpOffice\PhpWord\Settings; +use PhpOffice\PhpWord\Shared\Text as SharedText; +use PhpOffice\PhpWord\Shared\XMLWriter; /** * Abstract element writer @@ -32,7 +32,7 @@ abstract class AbstractElement /** * XML writer * - * @var \PhpOffice\Common\XMLWriter + * @var \PhpOffice\PhpWord\Shared\XMLWriter */ private $xmlWriter; @@ -58,7 +58,7 @@ abstract public function write(); /** * Create new instance * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Element\AbstractElement $element * @param bool $withoutP */ @@ -72,7 +72,7 @@ public function __construct(XMLWriter $xmlWriter, Element $element, $withoutP = /** * Get XML Writer * - * @return \PhpOffice\Common\XMLWriter + * @return \PhpOffice\PhpWord\Shared\XMLWriter */ protected function getXmlWriter() { @@ -207,7 +207,7 @@ private function writeTextStyle($styleType) */ protected function getText($text) { - return CommonText::controlCharacterPHP2OOXML($text); + return SharedText::controlCharacterPHP2OOXML($text); } /** diff --git a/src/PhpWord/Writer/Word2007/Element/Container.php b/src/PhpWord/Writer/Word2007/Element/Container.php index 892da051ad..0a39403d67 100644 --- a/src/PhpWord/Writer/Word2007/Element/Container.php +++ b/src/PhpWord/Writer/Word2007/Element/Container.php @@ -17,10 +17,10 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Element; -use PhpOffice\Common\XMLWriter; use PhpOffice\PhpWord\Element\AbstractContainer as ContainerElement; use PhpOffice\PhpWord\Element\AbstractElement as Element; use PhpOffice\PhpWord\Element\TextBreak as TextBreakElement; +use PhpOffice\PhpWord\Shared\XMLWriter; /** * Container element writer (section, textrun, header, footnote, cell, etc.) @@ -71,7 +71,7 @@ public function write() /** * Write individual element * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Element\AbstractElement $element * @param bool $withoutP * @return string diff --git a/src/PhpWord/Writer/Word2007/Element/FormField.php b/src/PhpWord/Writer/Word2007/Element/FormField.php index b59cf58f89..7206386431 100644 --- a/src/PhpWord/Writer/Word2007/Element/FormField.php +++ b/src/PhpWord/Writer/Word2007/Element/FormField.php @@ -17,8 +17,8 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Element; -use PhpOffice\Common\XMLWriter; use PhpOffice\PhpWord\Element\FormField as FormFieldElement; +use PhpOffice\PhpWord\Shared\XMLWriter; /** * FormField element writer @@ -105,7 +105,7 @@ public function write() * Write textinput. * * @see http://www.datypic.com/sc/ooxml/t-w_CT_FFTextInput.html - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Element\FormField $element */ private function writeTextInput(XMLWriter $xmlWriter, FormFieldElement $element) @@ -121,7 +121,7 @@ private function writeTextInput(XMLWriter $xmlWriter, FormFieldElement $element) * Write checkbox. * * @see http://www.datypic.com/sc/ooxml/t-w_CT_FFCheckBox.html - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Element\FormField $element */ private function writeCheckBox(XMLWriter $xmlWriter, FormFieldElement $element) @@ -144,7 +144,7 @@ private function writeCheckBox(XMLWriter $xmlWriter, FormFieldElement $element) * Write dropdown. * * @see http://www.datypic.com/sc/ooxml/t-w_CT_FFDDList.html - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Element\FormField $element */ private function writeDropDown(XMLWriter $xmlWriter, FormFieldElement $element) diff --git a/src/PhpWord/Writer/Word2007/Element/Image.php b/src/PhpWord/Writer/Word2007/Element/Image.php index 5bebb89c05..f136ba0b6c 100644 --- a/src/PhpWord/Writer/Word2007/Element/Image.php +++ b/src/PhpWord/Writer/Word2007/Element/Image.php @@ -17,8 +17,8 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Element; -use PhpOffice\Common\XMLWriter; use PhpOffice\PhpWord\Element\Image as ImageElement; +use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Style\Font as FontStyle; use PhpOffice\PhpWord\Style\Frame as FrameStyle; use PhpOffice\PhpWord\Writer\Word2007\Style\Font as FontStyleWriter; diff --git a/src/PhpWord/Writer/Word2007/Element/SDT.php b/src/PhpWord/Writer/Word2007/Element/SDT.php index edf89b5387..e496424253 100644 --- a/src/PhpWord/Writer/Word2007/Element/SDT.php +++ b/src/PhpWord/Writer/Word2007/Element/SDT.php @@ -17,8 +17,8 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Element; -use PhpOffice\Common\XMLWriter; use PhpOffice\PhpWord\Element\SDT as SDTElement; +use PhpOffice\PhpWord\Shared\XMLWriter; /** * Structured document tag element writer @@ -77,7 +77,7 @@ public function write() * Write text. * * @see http://www.datypic.com/sc/ooxml/t-w_CT_SdtText.html - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter */ private function writePlainText(XMLWriter $xmlWriter) { @@ -89,7 +89,7 @@ private function writePlainText(XMLWriter $xmlWriter) * Write combo box. * * @see http://www.datypic.com/sc/ooxml/t-w_CT_SdtComboBox.html - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Element\SDT $element */ private function writeComboBox(XMLWriter $xmlWriter, SDTElement $element) @@ -108,7 +108,7 @@ private function writeComboBox(XMLWriter $xmlWriter, SDTElement $element) * Write drop down list. * * @see http://www.datypic.com/sc/ooxml/t-w_CT_SdtDropDownList.html - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Element\SDT $element */ private function writeDropDownList(XMLWriter $xmlWriter, SDTElement $element) @@ -120,7 +120,7 @@ private function writeDropDownList(XMLWriter $xmlWriter, SDTElement $element) * Write date. * * @see http://www.datypic.com/sc/ooxml/t-w_CT_SdtDate.html - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Element\SDT $element */ private function writeDate(XMLWriter $xmlWriter, SDTElement $element) diff --git a/src/PhpWord/Writer/Word2007/Element/Shape.php b/src/PhpWord/Writer/Word2007/Element/Shape.php index 250d5c1d0d..ef30c48436 100644 --- a/src/PhpWord/Writer/Word2007/Element/Shape.php +++ b/src/PhpWord/Writer/Word2007/Element/Shape.php @@ -17,8 +17,8 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Element; -use PhpOffice\Common\XMLWriter; use PhpOffice\PhpWord\Element\Shape as ShapeElement; +use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Style\Shape as ShapeStyle; use PhpOffice\PhpWord\Writer\Word2007\Style\Shape as ShapeStyleWriter; @@ -77,7 +77,7 @@ public function write() /** * Write arc. * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Style\Shape $style */ private function writeArc(XMLWriter $xmlWriter, ShapeStyle $style) @@ -91,7 +91,7 @@ private function writeArc(XMLWriter $xmlWriter, ShapeStyle $style) /** * Write curve. * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Style\Shape $style */ private function writeCurve(XMLWriter $xmlWriter, ShapeStyle $style) @@ -106,7 +106,7 @@ private function writeCurve(XMLWriter $xmlWriter, ShapeStyle $style) /** * Write line. * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Style\Shape $style */ private function writeLine(XMLWriter $xmlWriter, ShapeStyle $style) @@ -120,7 +120,7 @@ private function writeLine(XMLWriter $xmlWriter, ShapeStyle $style) /** * Write polyline. * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Style\Shape $style */ private function writePolyline(XMLWriter $xmlWriter, ShapeStyle $style) @@ -131,7 +131,7 @@ private function writePolyline(XMLWriter $xmlWriter, ShapeStyle $style) /** * Write rectangle. * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Style\Shape $style */ private function writeRoundRect(XMLWriter $xmlWriter, ShapeStyle $style) diff --git a/src/PhpWord/Writer/Word2007/Element/TOC.php b/src/PhpWord/Writer/Word2007/Element/TOC.php index 94437cbf0d..3dac76fb4d 100644 --- a/src/PhpWord/Writer/Word2007/Element/TOC.php +++ b/src/PhpWord/Writer/Word2007/Element/TOC.php @@ -17,8 +17,8 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Element; -use PhpOffice\Common\XMLWriter; use PhpOffice\PhpWord\Element\TOC as TOCElement; +use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Style\Font; use PhpOffice\PhpWord\Writer\Word2007\Style\Font as FontStyleWriter; use PhpOffice\PhpWord\Writer\Word2007\Style\Paragraph as ParagraphStyleWriter; @@ -64,7 +64,7 @@ public function write() /** * Write title * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Element\TOC $element * @param \PhpOffice\PhpWord\Element\Title $title * @param bool $writeFieldMark @@ -132,7 +132,7 @@ private function writeTitle(XMLWriter $xmlWriter, TOCElement $element, $title, $ /** * Write style * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Element\TOC $element * @param int $indent */ @@ -178,7 +178,7 @@ private function writeStyle(XMLWriter $xmlWriter, TOCElement $element, $indent) /** * Write TOC Field. * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Element\TOC $element */ private function writeFieldMark(XMLWriter $xmlWriter, TOCElement $element) diff --git a/src/PhpWord/Writer/Word2007/Element/Table.php b/src/PhpWord/Writer/Word2007/Element/Table.php index c365b028ab..25a44fb11a 100644 --- a/src/PhpWord/Writer/Word2007/Element/Table.php +++ b/src/PhpWord/Writer/Word2007/Element/Table.php @@ -17,10 +17,10 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Element; -use PhpOffice\Common\XMLWriter; use PhpOffice\PhpWord\Element\Cell as CellElement; use PhpOffice\PhpWord\Element\Row as RowElement; use PhpOffice\PhpWord\Element\Table as TableElement; +use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Style\Cell as CellStyle; use PhpOffice\PhpWord\Style\Row as RowStyle; use PhpOffice\PhpWord\Writer\Word2007\Style\Cell as CellStyleWriter; @@ -71,7 +71,7 @@ public function write() /** * Write column. * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Element\Table $element */ private function writeColumns(XMLWriter $xmlWriter, TableElement $element) @@ -93,7 +93,7 @@ private function writeColumns(XMLWriter $xmlWriter, TableElement $element) /** * Write row. * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Element\Row $row */ private function writeRow(XMLWriter $xmlWriter, RowElement $row) @@ -119,7 +119,7 @@ private function writeRow(XMLWriter $xmlWriter, RowElement $row) /** * Write cell. * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Element\Cell $cell */ private function writeCell(XMLWriter $xmlWriter, CellElement $cell) diff --git a/src/PhpWord/Writer/Word2007/Part/AbstractPart.php b/src/PhpWord/Writer/Word2007/Part/AbstractPart.php index ce4e41cbd4..4bee5c542a 100644 --- a/src/PhpWord/Writer/Word2007/Part/AbstractPart.php +++ b/src/PhpWord/Writer/Word2007/Part/AbstractPart.php @@ -17,9 +17,9 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Part; -use PhpOffice\Common\XMLWriter; use PhpOffice\PhpWord\Exception\Exception; use PhpOffice\PhpWord\Settings; +use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Writer\AbstractWriter; /** @@ -73,7 +73,7 @@ public function getParentWriter() /** * Get XML Writer * - * @return \PhpOffice\Common\XMLWriter + * @return \PhpOffice\PhpWord\Shared\XMLWriter */ protected function getXmlWriter() { diff --git a/src/PhpWord/Writer/Word2007/Part/Chart.php b/src/PhpWord/Writer/Word2007/Part/Chart.php index 812d3bf1e3..8907160b22 100644 --- a/src/PhpWord/Writer/Word2007/Part/Chart.php +++ b/src/PhpWord/Writer/Word2007/Part/Chart.php @@ -17,8 +17,8 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Part; -use PhpOffice\Common\XMLWriter; use PhpOffice\PhpWord\Element\Chart as ChartElement; +use PhpOffice\PhpWord\Shared\XMLWriter; /** * Word2007 chart part writer: word/charts/chartx.xml @@ -99,7 +99,7 @@ public function write() * Write chart * * @see http://www.datypic.com/sc/ooxml/t-draw-chart_CT_Chart.html - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter */ private function writeChart(XMLWriter $xmlWriter) { @@ -121,7 +121,7 @@ private function writeChart(XMLWriter $xmlWriter) * @see http://www.datypic.com/sc/ooxml/t-draw-chart_CT_AreaChart.html * @see http://www.datypic.com/sc/ooxml/t-draw-chart_CT_RadarChart.html * @see http://www.datypic.com/sc/ooxml/t-draw-chart_CT_ScatterChart.html - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter */ private function writePlotArea(XMLWriter $xmlWriter) { @@ -209,7 +209,7 @@ private function writePlotArea(XMLWriter $xmlWriter) /** * Write series. * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param bool $scatter */ private function writeSeries(XMLWriter $xmlWriter, $scatter = false) @@ -294,7 +294,7 @@ private function writeSeries(XMLWriter $xmlWriter, $scatter = false) /** * Write series items. * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param string $type * @param array $values */ @@ -335,7 +335,7 @@ private function writeSeriesItem(XMLWriter $xmlWriter, $type, $values) * Write axis * * @see http://www.datypic.com/sc/ooxml/t-draw-chart_CT_CatAx.html - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param string $type */ private function writeAxis(XMLWriter $xmlWriter, $type) @@ -400,7 +400,7 @@ private function writeAxis(XMLWriter $xmlWriter, $type) * Write shape * * @see http://www.datypic.com/sc/ooxml/t-a_CT_ShapeProperties.html - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param bool $line */ private function writeShape(XMLWriter $xmlWriter, $line = false) diff --git a/src/PhpWord/Writer/Word2007/Part/Comments.php b/src/PhpWord/Writer/Word2007/Part/Comments.php index 33c9f59e6a..5b867324cb 100644 --- a/src/PhpWord/Writer/Word2007/Part/Comments.php +++ b/src/PhpWord/Writer/Word2007/Part/Comments.php @@ -17,8 +17,8 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Part; -use PhpOffice\Common\XMLWriter; use PhpOffice\PhpWord\Element\Comment; +use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Writer\Word2007\Element\Container; /** @@ -70,7 +70,7 @@ public function write() /** * Write comment item. * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Element\Comment $comment */ protected function writeComment(XMLWriter $xmlWriter, Comment $comment) diff --git a/src/PhpWord/Writer/Word2007/Part/ContentTypes.php b/src/PhpWord/Writer/Word2007/Part/ContentTypes.php index 28a2d29449..14fc585334 100644 --- a/src/PhpWord/Writer/Word2007/Part/ContentTypes.php +++ b/src/PhpWord/Writer/Word2007/Part/ContentTypes.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Part; -use PhpOffice\Common\XMLWriter; +use PhpOffice\PhpWord\Shared\XMLWriter; /** * Word2007 contenttypes part writer: [Content_Types].xml @@ -80,7 +80,7 @@ public function write() /** * Write content types element * - * @param \PhpOffice\Common\XMLWriter $xmlWriter XML Writer + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter XML Writer * @param array $parts * @param bool $isDefault */ diff --git a/src/PhpWord/Writer/Word2007/Part/Document.php b/src/PhpWord/Writer/Word2007/Part/Document.php index e0cabd7e1c..d2ab836b7e 100644 --- a/src/PhpWord/Writer/Word2007/Part/Document.php +++ b/src/PhpWord/Writer/Word2007/Part/Document.php @@ -17,8 +17,8 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Part; -use PhpOffice\Common\XMLWriter; use PhpOffice\PhpWord\Element\Section; +use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Writer\Word2007\Element\Container; use PhpOffice\PhpWord\Writer\Word2007\Style\Section as SectionStyleWriter; @@ -80,7 +80,7 @@ public function write() /** * Write begin section. * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Element\Section $section */ private function writeSection(XMLWriter $xmlWriter, Section $section) @@ -95,7 +95,7 @@ private function writeSection(XMLWriter $xmlWriter, Section $section) /** * Write end section. * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Element\Section $section */ private function writeSectionSettings(XMLWriter $xmlWriter, Section $section) diff --git a/src/PhpWord/Writer/Word2007/Part/Footnotes.php b/src/PhpWord/Writer/Word2007/Part/Footnotes.php index 59bf183096..58c2e9b170 100644 --- a/src/PhpWord/Writer/Word2007/Part/Footnotes.php +++ b/src/PhpWord/Writer/Word2007/Part/Footnotes.php @@ -17,8 +17,8 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Part; -use PhpOffice\Common\XMLWriter; use PhpOffice\PhpWord\Element\Footnote; +use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Writer\Word2007\Element\Container; use PhpOffice\PhpWord\Writer\Word2007\Style\Paragraph as ParagraphStyleWriter; @@ -135,7 +135,7 @@ public function setElements($elements) /** * Write note item. * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Element\Footnote|\PhpOffice\PhpWord\Element\Endnote $element */ protected function writeNote(XMLWriter $xmlWriter, $element) diff --git a/src/PhpWord/Writer/Word2007/Part/Numbering.php b/src/PhpWord/Writer/Word2007/Part/Numbering.php index 61e5cc2341..1b4f01a647 100644 --- a/src/PhpWord/Writer/Word2007/Part/Numbering.php +++ b/src/PhpWord/Writer/Word2007/Part/Numbering.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Part; -use PhpOffice\Common\XMLWriter; +use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Style; use PhpOffice\PhpWord\Style\Numbering as NumberingStyle; use PhpOffice\PhpWord\Style\NumberingLevel; @@ -97,7 +97,7 @@ public function write() /** * Write level. * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Style\NumberingLevel $level */ private function writeLevel(XMLWriter $xmlWriter, NumberingLevel $level) @@ -137,7 +137,7 @@ private function writeLevel(XMLWriter $xmlWriter, NumberingLevel $level) * * @since 0.11.0 * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Style\NumberingLevel $level * @todo Use paragraph style writer */ @@ -169,7 +169,7 @@ private function writeParagraph(XMLWriter $xmlWriter, NumberingLevel $level) * * @since 0.11.0 * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Style\NumberingLevel $level * @todo Use font style writer */ diff --git a/src/PhpWord/Writer/Word2007/Part/Rels.php b/src/PhpWord/Writer/Word2007/Part/Rels.php index 661a4fa862..70f632f7f3 100644 --- a/src/PhpWord/Writer/Word2007/Part/Rels.php +++ b/src/PhpWord/Writer/Word2007/Part/Rels.php @@ -17,8 +17,8 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Part; -use PhpOffice\Common\XMLWriter; use PhpOffice\PhpWord\Exception\Exception; +use PhpOffice\PhpWord\Shared\XMLWriter; /** * Word2007 main relationship writer: _rels/.rels @@ -49,7 +49,7 @@ public function write() /** * Write relationships. * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param array $xmlRels * @param array $mediaRels * @param int $relId @@ -76,7 +76,7 @@ protected function writeRels(XMLWriter $xmlWriter, $xmlRels = array(), $mediaRel /** * Write media relationships. * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param int $relId * @param array $mediaRel */ @@ -101,7 +101,7 @@ private function writeMediaRel(XMLWriter $xmlWriter, $relId, $mediaRel) * Format: * * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param int $relId Relationship ID * @param string $type Relationship type * @param string $target Relationship target diff --git a/src/PhpWord/Writer/Word2007/Part/Settings.php b/src/PhpWord/Writer/Word2007/Part/Settings.php index b764642a6a..4dd8b8bedf 100644 --- a/src/PhpWord/Writer/Word2007/Part/Settings.php +++ b/src/PhpWord/Writer/Word2007/Part/Settings.php @@ -17,9 +17,9 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Part; -use PhpOffice\Common\Microsoft\PasswordEncoder; use PhpOffice\PhpWord\ComplexType\ProofState; use PhpOffice\PhpWord\ComplexType\TrackChangesView; +use PhpOffice\PhpWord\Shared\Microsoft\PasswordEncoder; use PhpOffice\PhpWord\Style\Language; /** @@ -69,7 +69,7 @@ public function write() /** * Write indivual setting, recursive to any child settings. * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param string $settingKey * @param array|string $settingValue */ diff --git a/src/PhpWord/Writer/Word2007/Part/Styles.php b/src/PhpWord/Writer/Word2007/Part/Styles.php index d05338c77d..4d8f60c23a 100644 --- a/src/PhpWord/Writer/Word2007/Part/Styles.php +++ b/src/PhpWord/Writer/Word2007/Part/Styles.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Part; -use PhpOffice\Common\XMLWriter; +use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Style; use PhpOffice\PhpWord\Style\Font as FontStyle; use PhpOffice\PhpWord\Style\Paragraph as ParagraphStyle; @@ -76,7 +76,7 @@ public function write() /** * Write default font and other default styles. * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Style\AbstractStyle[] $styles */ private function writeDefaultStyles(XMLWriter $xmlWriter, $styles) @@ -161,7 +161,7 @@ private function writeDefaultStyles(XMLWriter $xmlWriter, $styles) /** * Write font style. * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param string $styleName * @param \PhpOffice\PhpWord\Style\Font $style */ @@ -229,7 +229,7 @@ private function writeFontStyle(XMLWriter $xmlWriter, $styleName, FontStyle $sty /** * Write paragraph style. * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param string $styleName * @param \PhpOffice\PhpWord\Style\Paragraph $style */ @@ -261,7 +261,7 @@ private function writeParagraphStyle(XMLWriter $xmlWriter, $styleName, Paragraph /** * Write table style. * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param string $styleName * @param \PhpOffice\PhpWord\Style\Table $style */ diff --git a/src/PhpWord/Writer/Word2007/Style/AbstractStyle.php b/src/PhpWord/Writer/Word2007/Style/AbstractStyle.php index fcd4aeb6cc..3624a7bef2 100644 --- a/src/PhpWord/Writer/Word2007/Style/AbstractStyle.php +++ b/src/PhpWord/Writer/Word2007/Style/AbstractStyle.php @@ -17,8 +17,8 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Style; -use PhpOffice\Common\XMLWriter; use PhpOffice\PhpWord\Settings; +use PhpOffice\PhpWord\Shared\XMLWriter; /** * Style writer @@ -30,7 +30,7 @@ abstract class AbstractStyle /** * XML writer * - * @var \PhpOffice\Common\XMLWriter + * @var \PhpOffice\PhpWord\Shared\XMLWriter */ private $xmlWriter; @@ -49,7 +49,7 @@ abstract public function write(); /** * Create new instance. * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param string|\PhpOffice\PhpWord\Style\AbstractStyle $style */ public function __construct(XMLWriter $xmlWriter, $style = null) @@ -61,7 +61,7 @@ public function __construct(XMLWriter $xmlWriter, $style = null) /** * Get XML Writer * - * @return \PhpOffice\Common\XMLWriter + * @return \PhpOffice\PhpWord\Shared\XMLWriter */ protected function getXmlWriter() { @@ -96,7 +96,7 @@ protected function convertTwip($value, $default = 0) ); $unit = Settings::getMeasurementUnit(); $factor = 1; - if (in_array($unit, $factors) && $value != $default) { + if (array_key_exists($unit, $factors) && $value != $default) { $factor = $factors[$unit]; } @@ -106,7 +106,7 @@ protected function convertTwip($value, $default = 0) /** * Write child style. * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param string $name * @param mixed $value */ diff --git a/src/PhpWord/Writer/Word2007/Style/Frame.php b/src/PhpWord/Writer/Word2007/Style/Frame.php index 10e5b151f7..782bce5219 100644 --- a/src/PhpWord/Writer/Word2007/Style/Frame.php +++ b/src/PhpWord/Writer/Word2007/Style/Frame.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Style; -use PhpOffice\Common\XMLWriter; +use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Style\Frame as FrameStyle; use PhpOffice\PhpWord\Writer\Word2007\Element\ParagraphAlignment; @@ -108,7 +108,7 @@ public function writeAlignment() /** * Write wrap. * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Style\Frame $style * @param string $wrap */ diff --git a/src/PhpWord/Writer/Word2007/Style/MarginBorder.php b/src/PhpWord/Writer/Word2007/Style/MarginBorder.php index f5c4b0153b..a992956359 100644 --- a/src/PhpWord/Writer/Word2007/Style/MarginBorder.php +++ b/src/PhpWord/Writer/Word2007/Style/MarginBorder.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Style; -use PhpOffice\Common\XMLWriter; +use PhpOffice\PhpWord\Shared\XMLWriter; /** * Margin border style writer @@ -78,7 +78,7 @@ public function write() /** * Write side. * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param string $side * @param int $width * @param string $color diff --git a/src/PhpWord/Writer/Word2007/Style/Paragraph.php b/src/PhpWord/Writer/Word2007/Style/Paragraph.php index 6761608608..08987a6a03 100644 --- a/src/PhpWord/Writer/Word2007/Style/Paragraph.php +++ b/src/PhpWord/Writer/Word2007/Style/Paragraph.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Style; -use PhpOffice\Common\XMLWriter; +use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Style; use PhpOffice\PhpWord\Style\Paragraph as ParagraphStyle; use PhpOffice\PhpWord\Writer\Word2007\Element\ParagraphAlignment; @@ -146,7 +146,7 @@ private function writeStyle() /** * Write tabs. * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Style\Tab[] $tabs */ private function writeTabs(XMLWriter $xmlWriter, $tabs) @@ -164,7 +164,7 @@ private function writeTabs(XMLWriter $xmlWriter, $tabs) /** * Write numbering. * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param array $numbering */ private function writeNumbering(XMLWriter $xmlWriter, $numbering) diff --git a/src/PhpWord/Writer/Word2007/Style/Table.php b/src/PhpWord/Writer/Word2007/Style/Table.php index 443d670582..eb040e019e 100644 --- a/src/PhpWord/Writer/Word2007/Style/Table.php +++ b/src/PhpWord/Writer/Word2007/Style/Table.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Style; -use PhpOffice\Common\XMLWriter; +use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\SimpleType\TblWidth; use PhpOffice\PhpWord\Style\Table as TableStyle; use PhpOffice\PhpWord\Writer\Word2007\Element\TableAlignment; @@ -59,7 +59,7 @@ public function write() /** * Write full style. * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Style\Table $style */ private function writeStyle(XMLWriter $xmlWriter, TableStyle $style) @@ -106,7 +106,7 @@ private function writeStyle(XMLWriter $xmlWriter, TableStyle $style) /** * Enable/Disable automatic resizing of the table * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param string $layout autofit / fixed */ private function writeLayout(XMLWriter $xmlWriter, $layout) @@ -119,7 +119,7 @@ private function writeLayout(XMLWriter $xmlWriter, $layout) /** * Write margin. * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Style\Table $style */ private function writeMargin(XMLWriter $xmlWriter, TableStyle $style) @@ -138,7 +138,7 @@ private function writeMargin(XMLWriter $xmlWriter, TableStyle $style) /** * Write border. * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Style\Table $style */ private function writeBorder(XMLWriter $xmlWriter, TableStyle $style) @@ -158,7 +158,7 @@ private function writeBorder(XMLWriter $xmlWriter, TableStyle $style) /** * Writes a table width * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param string $elementName * @param string $unit * @param int|float $width @@ -177,7 +177,7 @@ private function writeTblWidth(XMLWriter $xmlWriter, $elementName, $unit, $width /** * Write row style. * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Style\Table $style */ private function writeFirstRow(XMLWriter $xmlWriter, TableStyle $style) @@ -196,7 +196,7 @@ private function writeFirstRow(XMLWriter $xmlWriter, TableStyle $style) /** * Write shading. * - * @param \PhpOffice\Common\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Style\Table $style */ private function writeShading(XMLWriter $xmlWriter, TableStyle $style) diff --git a/tests/PhpWord/Element/ImageTest.php b/tests/PhpWord/Element/ImageTest.php index f56d079487..e83be708d7 100644 --- a/tests/PhpWord/Element/ImageTest.php +++ b/tests/PhpWord/Element/ImageTest.php @@ -77,10 +77,12 @@ public function testImages() foreach ($images as $imageData) { list($source, $type, $extension, $createFunction, $imageFunction) = $imageData; + $nam = ucfirst(strtok($source, '.')); $source = __DIR__ . "/../_files/images/{$source}"; - $image = new Image($source); + $image = new Image($source, null, null, $nam); $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Image', $image); $this->assertEquals($source, $image->getSource()); + $this->assertEquals($nam, $image->getName()); $this->assertEquals(md5($source), $image->getMediaId()); $this->assertEquals($type, $image->getImageType()); $this->assertEquals($extension, $image->getImageExtension()); diff --git a/tests/PhpWord/Element/TableTest.php b/tests/PhpWord/Element/TableTest.php index 8ae5306c82..17aa13a38f 100644 --- a/tests/PhpWord/Element/TableTest.php +++ b/tests/PhpWord/Element/TableTest.php @@ -99,10 +99,10 @@ public function testCountColumns() { $oTable = new Table(); $oTable->addRow(); - $element = $oTable->addCell(); + $oTable->addCell(); $this->assertEquals($oTable->countColumns(), 1); - $element = $oTable->addCell(); - $element = $oTable->addCell(); + $oTable->addCell(); + $oTable->addCell(); $this->assertEquals($oTable->countColumns(), 3); } } diff --git a/tests/PhpWord/Reader/Word2007/ElementTest.php b/tests/PhpWord/Reader/Word2007/ElementTest.php index cb72ef9f0a..08b72418ac 100644 --- a/tests/PhpWord/Reader/Word2007/ElementTest.php +++ b/tests/PhpWord/Reader/Word2007/ElementTest.php @@ -25,6 +25,46 @@ */ class ElementTest extends AbstractTestReader { + /** + * Test reading of alternate content value + */ + public function testReadAlternateContent() + { + $documentXml = ' + + + + + + + + + + + + + + Test node value + + + + + + + + + + '; + + $phpWord = $this->getDocumentFromString(array('document' => $documentXml)); + + $elements = $phpWord->getSection(0)->getElements(); + $this->assertInstanceOf('PhpOffice\PhpWord\Element\TextRun', $elements[0]); + $this->assertInstanceOf('PhpOffice\PhpWord\Element\Text', $elements[0]->getElement(0)); + $text = $elements[0]; + $this->assertEquals('Test node value', trim($text->getElement(0)->getText())); + } + /** * Test reading of textbreak */ diff --git a/tests/PhpWord/SettingsTest.php b/tests/PhpWord/SettingsTest.php index afe5954969..748ec71b10 100644 --- a/tests/PhpWord/SettingsTest.php +++ b/tests/PhpWord/SettingsTest.php @@ -25,6 +25,45 @@ */ class SettingsTest extends \PHPUnit\Framework\TestCase { + private $compatibility; + private $defaultFontSize; + private $defaultFontName; + private $defaultPaper; + private $measurementUnit; + private $outputEscapingEnabled; + private $pdfRendererName; + private $pdfRendererPath; + private $tempDir; + private $zipClass; + + public function setUp() + { + $this->compatibility = Settings::hasCompatibility(); + $this->defaultFontSize = Settings::getDefaultFontSize(); + $this->defaultFontName = Settings::getDefaultFontName(); + $this->defaultPaper = Settings::getDefaultPaper(); + $this->measurementUnit = Settings::getMeasurementUnit(); + $this->outputEscapingEnabled = Settings::isOutputEscapingEnabled(); + $this->pdfRendererName = Settings::getPdfRendererName(); + $this->pdfRendererPath = Settings::getPdfRendererPath(); + $this->tempDir = Settings::getTempDir(); + $this->zipClass = Settings::getZipClass(); + } + + public function tearDown() + { + Settings::setCompatibility($this->compatibility); + Settings::setDefaultFontSize($this->defaultFontSize); + Settings::setDefaultFontName($this->defaultFontName); + Settings::setDefaultPaper($this->defaultPaper); + Settings::setMeasurementUnit($this->measurementUnit); + Settings::setOutputEscapingEnabled($this->outputEscapingEnabled); + Settings::setPdfRendererName($this->pdfRendererName); + Settings::setPdfRendererPath($this->pdfRendererPath); + Settings::setTempDir($this->tempDir); + Settings::setZipClass($this->zipClass); + } + /** * Test set/get compatibity option */ @@ -35,14 +74,28 @@ public function testSetGetCompatibility() $this->assertFalse(Settings::hasCompatibility()); } + /** + * Test set/get outputEscapingEnabled option + */ + public function testSetGetOutputEscapingEnabled() + { + $this->assertFalse(Settings::isOutputEscapingEnabled()); + Settings::setOutputEscapingEnabled(true); + $this->assertTrue(Settings::isOutputEscapingEnabled()); + } + /** * Test set/get zip class */ public function testSetGetZipClass() { + $this->assertEquals(Settings::ZIPARCHIVE, Settings::getZipClass()); + $this->assertFalse(Settings::setZipClass('foo')); $this->assertEquals(Settings::ZIPARCHIVE, Settings::getZipClass()); $this->assertTrue(Settings::setZipClass(Settings::PCLZIP)); + $this->assertEquals(Settings::getZipClass(), Settings::PCLZIP); $this->assertFalse(Settings::setZipClass('foo')); + $this->assertEquals(Settings::getZipClass(), Settings::PCLZIP); } /** @@ -57,6 +110,7 @@ public function testSetGetPdfRenderer() $this->assertEquals(Settings::PDF_RENDERER_DOMPDF, Settings::getPdfRendererName()); $this->assertEquals($domPdfPath, Settings::getPdfRendererPath()); $this->assertFalse(Settings::setPdfRendererPath('dummy/path')); + $this->assertEquals($domPdfPath, Settings::getPdfRendererPath()); } /** @@ -64,9 +118,13 @@ public function testSetGetPdfRenderer() */ public function testSetGetMeasurementUnit() { + $this->assertEquals(Settings::UNIT_TWIP, Settings::getMeasurementUnit()); + $this->assertFalse(Settings::setMeasurementUnit('foo')); $this->assertEquals(Settings::UNIT_TWIP, Settings::getMeasurementUnit()); $this->assertTrue(Settings::setMeasurementUnit(Settings::UNIT_INCH)); + $this->assertEquals(Settings::UNIT_INCH, Settings::getMeasurementUnit()); $this->assertFalse(Settings::setMeasurementUnit('foo')); + $this->assertEquals(Settings::UNIT_INCH, Settings::getMeasurementUnit()); } /** @@ -98,9 +156,13 @@ public function testTempDirCanBeSet() */ public function testSetGetDefaultFontName() { + $this->assertEquals(Settings::DEFAULT_FONT_NAME, Settings::getDefaultFontName()); + $this->assertFalse(Settings::setDefaultFontName(' ')); $this->assertEquals(Settings::DEFAULT_FONT_NAME, Settings::getDefaultFontName()); $this->assertTrue(Settings::setDefaultFontName('Times New Roman')); + $this->assertEquals('Times New Roman', Settings::getDefaultFontName()); $this->assertFalse(Settings::setDefaultFontName(' ')); + $this->assertEquals('Times New Roman', Settings::getDefaultFontName()); } /** @@ -108,9 +170,36 @@ public function testSetGetDefaultFontName() */ public function testSetGetDefaultFontSize() { + $this->assertEquals(Settings::DEFAULT_FONT_SIZE, Settings::getDefaultFontSize()); + $this->assertFalse(Settings::setDefaultFontSize(null)); $this->assertEquals(Settings::DEFAULT_FONT_SIZE, Settings::getDefaultFontSize()); $this->assertTrue(Settings::setDefaultFontSize(12)); + $this->assertEquals(12, Settings::getDefaultFontSize()); $this->assertFalse(Settings::setDefaultFontSize(null)); + $this->assertEquals(12, Settings::getDefaultFontSize()); + } + + /** + * Test set/get default paper + */ + public function testSetGetDefaultPaper() + { + $dflt = Settings::DEFAULT_PAPER; + $chng = ($dflt === 'A4') ? 'Letter' : 'A4'; + $doc = new PhpWord(); + $this->assertEquals($dflt, Settings::getDefaultPaper()); + $sec1 = $doc->addSection(); + $this->assertEquals($dflt, $sec1->getStyle()->getPaperSize()); + $this->assertFalse(Settings::setDefaultPaper('')); + $this->assertEquals($dflt, Settings::getDefaultPaper()); + $this->assertTrue(Settings::setDefaultPaper($chng)); + $this->assertEquals($chng, Settings::getDefaultPaper()); + $sec2 = $doc->addSection(); + $this->assertEquals($chng, $sec2->getStyle()->getPaperSize()); + $sec3 = $doc->addSection(array('paperSize' => 'Legal')); + $this->assertEquals('Legal', $sec3->getStyle()->getPaperSize()); + $this->assertFalse(Settings::setDefaultPaper('')); + $this->assertEquals($chng, Settings::getDefaultPaper()); } /** @@ -126,6 +215,7 @@ public function testLoadConfig() 'defaultFontName' => 'Arial', 'defaultFontSize' => 10, 'outputEscapingEnabled' => false, + 'defaultPaper' => 'A4', ); // Test default value @@ -133,6 +223,16 @@ public function testLoadConfig() // Test with valid file $this->assertEquals($expected, Settings::loadConfig(__DIR__ . '/../../phpword.ini.dist')); + foreach ($expected as $key => $value) { + if ($key === 'compatibility') { + $meth = 'hasCompatibility'; + } elseif ($key === 'outputEscapingEnabled') { + $meth = 'isOutputEscapingEnabled'; + } else { + $meth = 'get' . ucfirst($key); + } + $this->assertEquals(Settings::$meth(), $value); + } // Test with invalid file $this->assertEmpty(Settings::loadConfig(__DIR__ . '/../../phpunit.xml.dist')); diff --git a/tests/PhpWord/Shared/ConverterTest.php b/tests/PhpWord/Shared/ConverterTest.php index 0d10dc4936..668837742b 100644 --- a/tests/PhpWord/Shared/ConverterTest.php +++ b/tests/PhpWord/Shared/ConverterTest.php @@ -131,5 +131,8 @@ public function testCssSizeParser() $this->assertEquals(120, Converter::cssToPoint('10pc')); $this->assertEquals(28.346457, Converter::cssToPoint('10mm'), '', 0.000001); $this->assertEquals(283.464567, Converter::cssToPoint('10cm'), '', 0.000001); + $this->assertEquals(40, Converter::cssToPixel('30pt')); + $this->assertEquals(1.27, Converter::cssToCm('36pt')); + $this->assertEquals(127000, Converter::cssToEmu('10pt')); } } diff --git a/tests/PhpWord/Shared/DrawingTest.php b/tests/PhpWord/Shared/DrawingTest.php new file mode 100644 index 0000000000..b7110923d3 --- /dev/null +++ b/tests/PhpWord/Shared/DrawingTest.php @@ -0,0 +1,112 @@ +assertEquals(0, Drawing::degreesToAngle()); + $this->assertEquals((int) round($value * 60000), Drawing::degreesToAngle($value)); + $this->assertEquals(0, Drawing::angleToDegrees()); + $this->assertEquals(round($value / 60000), Drawing::angleToDegrees($value)); + } + + public function testPixelsCentimeters() + { + $value = rand(1, 100); + + $this->assertEquals(0, Drawing::pixelsToCentimeters()); + $this->assertEquals($value / Drawing::DPI_96 * 2.54, Drawing::pixelsToCentimeters($value)); + $this->assertEquals(0, Drawing::centimetersToPixels()); + $this->assertEquals($value / 2.54 * Drawing::DPI_96, Drawing::centimetersToPixels($value)); + } + + public function testPixelsEMU() + { + $value = rand(1, 100); + + $this->assertEquals(0, Drawing::pixelsToEmu()); + $this->assertEquals(round($value * 9525), Drawing::pixelsToEmu($value)); + $this->assertEquals(0, Drawing::emuToPixels()); + $this->assertEquals(round($value / 9525), Drawing::emuToPixels($value)); + } + + public function testPixelsPoints() + { + $value = rand(1, 100); + + $this->assertEquals(0, Drawing::pixelsToPoints()); + $this->assertEquals($value * 0.67777777, Drawing::pixelsToPoints($value)); + $this->assertEquals(0, Drawing::pointsToPixels()); + $this->assertEquals($value * 1.333333333, Drawing::pointsToPixels($value)); + } + + public function testPointsCentimeters() + { + $value = rand(1, 100); + + $this->assertEquals(0, Drawing::pointsToCentimeters()); + $this->assertEquals($value * 1.333333333 / Drawing::DPI_96 * 2.54, Drawing::pointsToCentimeters($value)); + } + + public function testTwips() + { + $value = rand(1, 100); + + // Centimeters + $this->assertEquals(0, Drawing::centimetersToTwips()); + $this->assertEquals($value * 566.928, Drawing::centimetersToTwips($value)); + + $this->assertEquals(0, Drawing::twipsToCentimeters()); + $this->assertEquals($value / 566.928, Drawing::twipsToCentimeters($value)); + + // Inches + $this->assertEquals(0, Drawing::inchesToTwips()); + $this->assertEquals($value * 1440, Drawing::inchesToTwips($value)); + + $this->assertEquals(0, Drawing::twipsToInches()); + $this->assertEquals($value / 1440, Drawing::twipsToInches($value)); + + // Pixels + $this->assertEquals(0, Drawing::twipsToPixels()); + $this->assertEquals(round($value / 15.873984), Drawing::twipsToPixels($value)); + } + + public function testHTML() + { + $this->assertFalse(Drawing::htmlToRGB('0')); + $this->assertFalse(Drawing::htmlToRGB('00')); + $this->assertFalse(Drawing::htmlToRGB('0000')); + $this->assertFalse(Drawing::htmlToRGB('00000')); + + $this->assertInternalType('array', Drawing::htmlToRGB('ABCDEF')); + $this->assertCount(3, Drawing::htmlToRGB('ABCDEF')); + $this->assertEquals(array(0xAB, 0xCD, 0xEF), Drawing::htmlToRGB('ABCDEF')); + $this->assertEquals(array(0xAB, 0xCD, 0xEF), Drawing::htmlToRGB('#ABCDEF')); + $this->assertEquals(array(0xAA, 0xBB, 0xCC), Drawing::htmlToRGB('ABC')); + $this->assertEquals(array(0xAA, 0xBB, 0xCC), Drawing::htmlToRGB('#ABC')); + } +} diff --git a/tests/PhpWord/Shared/Microsoft/PasswordEncoderTest.php b/tests/PhpWord/Shared/Microsoft/PasswordEncoderTest.php new file mode 100644 index 0000000000..47fb54814d --- /dev/null +++ b/tests/PhpWord/Shared/Microsoft/PasswordEncoderTest.php @@ -0,0 +1,88 @@ +assertEquals('M795/MAlmGU8RIsY9Q9uDLHC7bk=', $hashPassword); + } + + /** + * Test that a password can be hashed with a custom salt + */ + public function testEncodePasswordWithSalt() + { + //given + $password = 'test'; + $salt = base64_decode('uq81pJRRGFIY5U+E9gt8tA=='); + + //when + $hashPassword = PasswordEncoder::hashPassword($password, PasswordEncoder::ALGORITHM_SHA_1, $salt); + + //then + $this->assertEquals('QiDOcpia1YzSVJPiKPwWebl9p/0=', $hashPassword); + } + + /** + * Test that the encoder falls back on SHA-1 if a non supported algorithm is given + */ + public function testDefaultsToSha1IfUnsupportedAlgorithm() + { + //given + $password = 'test'; + $salt = base64_decode('uq81pJRRGFIY5U+E9gt8tA=='); + + //when + $hashPassword = PasswordEncoder::hashPassword($password, PasswordEncoder::ALGORITHM_MAC, $salt); + + //then + $this->assertEquals('QiDOcpia1YzSVJPiKPwWebl9p/0=', $hashPassword); + } + + /** + * Test that the encoder falls back on SHA-1 if a non supported algorithm is given + */ + public function testEncodePasswordWithNullAsciiCodeInPassword() + { + //given + $password = 'test' . chr(0); + $salt = base64_decode('uq81pJRRGFIY5U+E9gt8tA=='); + + //when + $hashPassword = PasswordEncoder::hashPassword($password, PasswordEncoder::ALGORITHM_MAC, $salt, 1); + + //then + $this->assertEquals('rDV9sgdDsztoCQlvRCb1lF2wxNg=', $hashPassword); + } +} diff --git a/tests/PhpWord/Shared/TextTest.php b/tests/PhpWord/Shared/TextTest.php new file mode 100644 index 0000000000..6df19b1250 --- /dev/null +++ b/tests/PhpWord/Shared/TextTest.php @@ -0,0 +1,87 @@ +assertEquals('', Text::controlCharacterPHP2OOXML()); + $this->assertEquals('aeiou', Text::controlCharacterPHP2OOXML('aeiou')); + $this->assertEquals('àéîöù', Text::controlCharacterPHP2OOXML('àéîöù')); + + $value = rand(0, 8); + $this->assertEquals('_x' . sprintf('%04s', strtoupper(dechex($value))) . '_', Text::controlCharacterPHP2OOXML(chr($value))); + + $this->assertEquals('', Text::controlCharacterOOXML2PHP('')); + $this->assertEquals(chr(0x08), Text::controlCharacterOOXML2PHP('_x0008_')); + } + + public function testNumberFormat() + { + $this->assertEquals('2.1', Text::numberFormat('2.06', 1)); + $this->assertEquals('2.1', Text::numberFormat('2.12', 1)); + $this->assertEquals('1234.0', Text::numberFormat(1234, 1)); + } + + public function testChr() + { + $this->assertEquals('A', Text::chr(65)); + $this->assertEquals('A', Text::chr(0x41)); + $this->assertEquals('é', Text::chr(233)); + $this->assertEquals('é', Text::chr(0xE9)); + $this->assertEquals('⼳', Text::chr(12083)); + $this->assertEquals('⼳', Text::chr(0x2F33)); + $this->assertEquals('🌃', Text::chr(127747)); + $this->assertEquals('🌃', Text::chr(0x1F303)); + $this->assertEquals('', Text::chr(2097152)); + } + + /** + * Is UTF8 + */ + public function testIsUTF8() + { + $this->assertTrue(Text::isUTF8('')); + $this->assertTrue(Text::isUTF8('éééé')); + $this->assertFalse(Text::isUTF8(utf8_decode('éééé'))); + } + + /** + * Test unicode conversion + */ + public function testToUnicode() + { + $this->assertEquals('a', Text::toUnicode('a')); + $this->assertEquals('\uc0{\u8364}', Text::toUnicode('€')); + $this->assertEquals('\uc0{\u233}', Text::toUnicode('é')); + } + + /** + * Test remove underscore prefix + */ + public function testRemoveUnderscorePrefix() + { + $this->assertEquals('item', Text::removeUnderscorePrefix('_item')); + } +} diff --git a/tests/PhpWord/Shared/XMLReaderTest.php b/tests/PhpWord/Shared/XMLReaderTest.php new file mode 100644 index 0000000000..4d0ee64ca7 --- /dev/null +++ b/tests/PhpWord/Shared/XMLReaderTest.php @@ -0,0 +1,134 @@ +getDomFromString('AAA'); + + $this->assertTrue($reader->elementExists('/element/child')); + $this->assertEquals('AAA', $reader->getElement('/element/child')->textContent); + $this->assertEquals('AAA', $reader->getValue('/element/child')); + $this->assertEquals('test', $reader->getAttribute('attr', $reader->getElement('/element'))); + $this->assertEquals('subtest', $reader->getAttribute('attr', $reader->getElement('/element'), 'child')); + } + + /** + * Test reading XML from zip + */ + public function testDomFromZip() + { + $archiveFile = __DIR__ . '/../_files/xml/reader.zip'; + + $reader = new XMLReader(); + $reader->getDomFromZip($archiveFile, 'test.xml'); + + $this->assertTrue($reader->elementExists('/element/child')); + + $this->assertFalse($reader->getDomFromZip($archiveFile, 'non_existing_xml_file.xml')); + } + + /** + * Test that read from non existing archive throws exception + * + * @expectedException \Exception + */ + public function testThrowsExceptionOnNonExistingArchive() + { + $archiveFile = __DIR__ . '/../_files/xml/readers.zip'; + + $reader = new XMLReader(); + $reader->getDomFromZip($archiveFile, 'test.xml'); + } + + /** + * Test elements count + */ + public function testCountElements() + { + $reader = new XMLReader(); + $reader->getDomFromString('AAABBB'); + + $this->assertEquals(2, $reader->countElements('/element/child')); + } + + /** + * Test read non existing elements + */ + public function testReturnNullOnNonExistingNode() + { + $reader = new XMLReader(); + $this->assertEmpty($reader->getElements('/element/children')); + $reader->getDomFromString('AAA'); + + $this->assertNull($reader->getElement('/element/children')); + $this->assertNull($reader->getValue('/element/children')); + } + + /** + * Test that xpath fails if custom namespace is not registered + */ + public function testShouldThrowExceptionIfNamespaceIsNotKnown() + { + try { + $reader = new XMLReader(); + $reader->getDomFromString('AAA'); + + $this->assertTrue($reader->elementExists('/element/test:child')); + $this->assertEquals('AAA', $reader->getElement('/element/test:child')->textContent); + $this->fail(); + } catch (\Exception $e) { + $this->assertTrue(true); + } + } + + /** + * Test reading XML with manually registered namespace + */ + public function testShouldParseXmlWithCustomNamespace() + { + $reader = new XMLReader(); + $reader->getDomFromString('AAA'); + $reader->registerNamespace('test', 'http://phpword.com/my/custom/namespace'); + + $this->assertTrue($reader->elementExists('/element/test:child')); + $this->assertEquals('AAA', $reader->getElement('/element/test:child')->textContent); + } + + /** + * Test that xpath fails if custom namespace is not registered + * + * @expectedException \InvalidArgumentException + */ + public function testShouldThowExceptionIfTryingToRegisterNamespaceBeforeReadingDoc() + { + $reader = new XMLReader(); + $reader->registerNamespace('test', 'http://phpword.com/my/custom/namespace'); + } +} diff --git a/tests/PhpWord/Shared/XMLWriterTest.php b/tests/PhpWord/Shared/XMLWriterTest.php new file mode 100644 index 0000000000..e86cd50b02 --- /dev/null +++ b/tests/PhpWord/Shared/XMLWriterTest.php @@ -0,0 +1,71 @@ +startElement('element'); + $object->text('AAA'); + $object->endElement(); + $this->assertEquals('AAA' . chr(10), $object->getData()); + + // Disk + $object = new XMLWriter(XMLWriter::STORAGE_DISK); + $object->startElement('element'); + $object->text('BBB'); + $object->endElement(); + $this->assertEquals('BBB' . chr(10), $object->getData()); + } + + public function testWriteAttribute() + { + $xmlWriter = new XMLWriter(); + $xmlWriter->startElement('element'); + $xmlWriter->writeAttribute('name', 'value'); + $xmlWriter->endElement(); + + $this->assertSame('' . chr(10), $xmlWriter->getData()); + } + + public function testWriteAttributeShouldWriteFloatValueLocaleIndependent() + { + $value = 1.2; + + $xmlWriter = new XMLWriter(); + $xmlWriter->startElement('element'); + $xmlWriter->writeAttribute('name', $value); + $xmlWriter->endElement(); + + $currentLocale = setlocale(LC_NUMERIC, 0); + + setlocale(LC_NUMERIC, 'de_DE.UTF-8', 'de'); + + $this->assertSame('' . chr(10), $xmlWriter->getData()); + + setlocale(LC_NUMERIC, $currentLocale); + } +} diff --git a/tests/PhpWord/TemplateProcessorTest.php b/tests/PhpWord/TemplateProcessorTest.php index 4caca77aeb..5b922f714a 100644 --- a/tests/PhpWord/TemplateProcessorTest.php +++ b/tests/PhpWord/TemplateProcessorTest.php @@ -140,6 +140,11 @@ final public function testXslStyleSheetCanBeApplied($actualDocumentFqfn) */ final public function testXslStyleSheetCanNotBeAppliedOnFailureOfSettingParameterValue() { + // Test is not needed for PHP 8.0, because internally validation throws TypeError exception. + if (\PHP_VERSION_ID >= 80000) { + $this->markTestSkipped('not needed for PHP 8.0'); + } + $templateProcessor = new TemplateProcessor(__DIR__ . '/_files/templates/blank.docx'); $xslDomDocument = new \DOMDocument(); diff --git a/tests/PhpWord/Writer/ODText/Element/ImageTest.php b/tests/PhpWord/Writer/ODText/Element/ImageTest.php new file mode 100644 index 0000000000..2e0fdeefc0 --- /dev/null +++ b/tests/PhpWord/Writer/ODText/Element/ImageTest.php @@ -0,0 +1,65 @@ +addSection(); + $section->addImage(__DIR__ . '/../../../_files/images/earth.jpg'); + $section->addImage(__DIR__ . '/../../../_files/images/mario.gif', array('align' => 'end')); + $doc = TestHelperDOCX::getDocument($phpWord, 'ODText'); + $s2a = '/office:document-content/office:automatic-styles'; + $element = "$s2a/style:style[3]"; + $this->assertEquals('IM1', $doc->getElementAttribute($element, 'style:name')); + $element .= '/style:paragraph-properties'; + $this->assertEquals('', $doc->getElementAttribute($element, 'fo:text-align')); + $element = "$s2a/style:style[4]"; + $this->assertEquals('IM2', $doc->getElementAttribute($element, 'style:name')); + $element .= '/style:paragraph-properties'; + $this->assertEquals('end', $doc->getElementAttribute($element, 'fo:text-align')); + + $path = '/office:document-content/office:body/office:text/text:section/text:p[2]'; + $this->assertTrue($doc->elementExists($path)); + $this->assertEquals('IM1', $doc->getElementAttribute($path, 'text:style-name')); + $path = '/office:document-content/office:body/office:text/text:section/text:p[3]'; + $this->assertTrue($doc->elementExists($path)); + $this->assertEquals('IM2', $doc->getElementAttribute($path, 'text:style-name')); + } +} diff --git a/tests/PhpWord/Writer/ODText/ElementTest.php b/tests/PhpWord/Writer/ODText/ElementTest.php index 37f0d1ef52..8b82734742 100644 --- a/tests/PhpWord/Writer/ODText/ElementTest.php +++ b/tests/PhpWord/Writer/ODText/ElementTest.php @@ -17,8 +17,9 @@ namespace PhpOffice\PhpWord\Writer\ODText; -use PhpOffice\Common\XMLWriter; +use PhpOffice\PhpWord\Element\TrackChange; use PhpOffice\PhpWord\PhpWord; +use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\TestHelperDOCX; /** @@ -26,12 +27,20 @@ */ class ElementTest extends \PHPUnit\Framework\TestCase { + /** + * Executed after each method of the class + */ + public function tearDown() + { + TestHelperDOCX::clear(); + } + /** * Test unmatched elements */ public function testUnmatchedElements() { - $elements = array('Image', 'Link', 'Table', 'Text', 'Title'); + $elements = array('Image', 'Link', 'Table', 'Text', 'Title', 'Field'); foreach ($elements as $element) { $objectClass = 'PhpOffice\\PhpWord\\Writer\\ODText\\Element\\' . $element; $xmlWriter = new XMLWriter(); @@ -39,8 +48,207 @@ public function testUnmatchedElements() $object = new $objectClass($xmlWriter, $newElement); $object->write(); - $this->assertEquals('', $xmlWriter->getData()); + self::assertEquals('', $xmlWriter->getData()); + } + } + + // ODT Line Element not yet implemented + // ODT Bookmark not yet implemented + // ODT Table with style name not yet implemented (Word test defective) + // ODT Shape Elements not yet implemented + // ODT Chart Elements not yet implemented + // ODT adding Field to Section not yet implemented + // ODT List not yet implemented + // ODT Macro Button not yet implemented + // ODT Form Field not yet implemented + // ODT SDT not yet implemented + // ODT Comment not yet implemented + // ODT Track Changes implemented, possibly not correctly + // ODT List Item not yet implemented + + /** + * Test link element + */ + public function testLinkElement() + { + $phpWord = new PhpWord(); + $section = $phpWord->addSection(); + + $extlink = 'https://github.com/PHPOffice/PHPWord'; + $section->addLink($extlink); + $intlink = 'internal_link'; + $section->addLink($intlink, null, null, null, true); + $doc = TestHelperDOCX::getDocument($phpWord, 'ODText'); + + $p2t = '/office:document-content/office:body/office:text/text:section'; + $element = "$p2t/text:p[2]/text:a"; + self::assertTrue($doc->elementExists($element)); + self::assertEquals($extlink, $doc->getElementAttribute($element, 'xlink:href')); + + $element = "$p2t/text:p[3]/text:a"; + self::assertTrue($doc->elementExists($element)); + self::assertEquals("#$intlink", $doc->getElementAttribute($element, 'xlink:href')); + } + + /** + * Basic test for table element + */ + public function testTableElements() + { + $phpWord = new PhpWord(); + $section = $phpWord->addSection(); + + $table = $section->addTable(array('alignment' => \PhpOffice\PhpWord\SimpleType\JcTable::CENTER)); + $table->addRow(900); + $table->addCell(2000)->addText('Row 1'); + $table->addCell(2000)->addText('Row 2'); + $table->addCell(2000)->addText('Row 3'); + $table->addCell(2000)->addText('Row 4'); + + $doc = TestHelperDOCX::getDocument($phpWord, 'ODText'); + + $p2s = '/office:document-content/office:automatic-styles'; + $tableStyleNum = 1; + $tableStyleName = ''; + while ($tableStyleName === '') { + $element = "$p2s/style:style[$tableStyleNum]"; + if (!$doc->elementExists($element)) { + break; + } + if ($doc->getElementAttribute($element, 'style:family') === 'table') { + $tableStyleName = $doc->getElementAttribute($element, 'style:name'); + break; + } + ++$tableStyleNum; } + self::AssertNotEquals('', $tableStyleName); + $element = "$element/style:table-properties"; + self::assertTrue($doc->elementExists($element)); + self::assertEquals(\PhpOffice\PhpWord\SimpleType\JcTable::CENTER, $doc->getElementAttribute($element, 'table:align')); + $p2t = '/office:document-content/office:body/office:text/text:section'; + $tableRootElement = "$p2t/table:table"; + self::assertTrue($doc->elementExists($tableRootElement)); + self::assertEquals($tableStyleName, $doc->getElementAttribute($tableRootElement, 'table:style')); + self::assertTrue($doc->elementExists($tableRootElement . '/table:table-column[4]')); + } + + /** + * Test Title and Headings + */ + public function testTitleAndHeading() + { + $phpWord = new PhpWord(); + $phpWord->addTitleStyle(0, array('size' => 14, 'italic' => true)); + $phpWord->addTitleStyle(1, array('size' => 20, 'color' => '333333', 'bold' => true)); + + $section = $phpWord->addSection(); + $section->addTitle('This is a title', 0); + $section->addTitle('Heading 1', 1); + + $doc = TestHelperDOCX::getDocument($phpWord, 'ODText'); + + $p2t = '/office:document-content/office:body/office:text/text:section'; + $element = "$p2t/text:h[1]"; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('HE0', $doc->getElementAttribute($element, 'text:style-name')); + $this->assertEquals('0', $doc->getElementAttribute($element, 'text:outline-level')); + $span = "$element/text:span"; + $this->assertTrue($doc->elementExists($span)); + $this->assertEquals('This is a title', $doc->getElement($span)->textContent); + $this->assertEquals('Title', $doc->getElementAttribute($span, 'text:style-name')); + + $element = "$p2t/text:h[2]"; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('HD1', $doc->getElementAttribute($element, 'text:style-name')); + $this->assertEquals('1', $doc->getElementAttribute($element, 'text:outline-level')); + $span = "$element/text:span"; + $this->assertTrue($doc->elementExists($span)); + $this->assertEquals('Heading 1', $doc->getElement($span)->textContent); + $this->assertEquals('Heading_1', $doc->getElementAttribute($span, 'text:style-name')); + + $doc->setDefaultFile('styles.xml'); + $element = '/office:document-styles/office:styles/style:style[1]'; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('Title', $doc->getElementAttribute($element, 'style:name')); + $element .= '/style:text-properties'; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('14pt', $doc->getElementAttribute($element, 'fo:font-size')); + $this->assertEquals('italic', $doc->getElementAttribute($element, 'fo:font-style')); + $this->assertEquals('', $doc->getElementAttribute($element, 'fo:font-weight')); + $this->assertEquals('', $doc->getElementAttribute($element, 'fo:color')); + + $element = '/office:document-styles/office:styles/style:style[2]'; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('Heading_1', $doc->getElementAttribute($element, 'style:name')); + $element .= '/style:text-properties'; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('20pt', $doc->getElementAttribute($element, 'fo:font-size')); + $this->assertEquals('', $doc->getElementAttribute($element, 'fo:font-style')); + $this->assertEquals('bold', $doc->getElementAttribute($element, 'fo:font-weight')); + $this->assertEquals('#333333', $doc->getElementAttribute($element, 'fo:color')); + } + + /** + * Test title specified as text run rather than text + */ + public function testTextRunTitle() + { + $phpWord = new \PhpOffice\PhpWord\PhpWord(); + $phpWord->addTitleStyle(1, array('name' => 'Times New Roman', 'size' => 18, 'bold' => true)); + $section = $phpWord->addSection(); + $section->addTitle('Text Title', 1); + $section->addText('Text following Text Title'); + $textRun = new \PhpOffice\PhpWord\Element\TextRun(); + $textRun->addText('Text Run'); + $textRun->addText(' Title'); + $section->addTitle($textRun, 1); + $section->addText('Text following Text Run Title'); + + $doc = TestHelperDOCX::getDocument($phpWord, 'ODText'); + + $p2t = '/office:document-content/office:body/office:text/text:section'; + + $element = "$p2t/text:h[1]"; + $this->assertEquals('HE1', $doc->getElementAttribute($element, 'text:style-name')); + $this->assertEquals('1', $doc->getElementAttribute($element, 'text:outline-level')); + $span = "$element/text:span"; + $this->assertEquals('Text Title', $doc->getElement($span)->textContent); + $this->assertEquals('Heading_1', $doc->getElementAttribute($span, 'text:style-name')); + $element = "$p2t/text:p[2]/text:span"; + $this->assertEquals('Text following Text Title', $doc->getElement($element)->nodeValue); + + $element = "$p2t/text:h[2]"; + $this->assertEquals('HD1', $doc->getElementAttribute($element, 'text:style-name')); + $this->assertEquals('1', $doc->getElementAttribute($element, 'text:outline-level')); + $span = "$element/text:span"; + $this->assertEquals('Text Run', $doc->getElement("$span/text:span[1]")->textContent); + $this->assertTrue($doc->elementExists("$span/text:span[2]/text:s")); + $this->assertEquals('Title', $doc->getElement("$span/text:span[2]")->textContent); + $this->assertEquals('Heading_1', $doc->getElementAttribute($span, 'text:style-name')); + $element = "$p2t/text:p[3]/text:span"; + $this->assertEquals('Text following Text Run Title', $doc->getElement($element)->nodeValue); + } + + /** + * Test correct writing of text with ampersand in it + */ + public function testTextWithAmpersand() + { + $esc = \PhpOffice\PhpWord\Settings::isOutputEscapingEnabled(); + \PhpOffice\PhpWord\Settings::setOutputEscapingEnabled(true); + $phpWord = new PhpWord(); + $section = $phpWord->addSection(); + $txt = 'this text contains an & (ampersand)'; + $section->addText($txt); + + $doc = TestHelperDOCX::getDocument($phpWord, 'ODText'); + \PhpOffice\PhpWord\Settings::setOutputEscapingEnabled($esc); + $p2t = '/office:document-content/office:body/office:text/text:section'; + $element = "$p2t/text:p[2]"; + $this->assertTrue($doc->elementExists($element)); + $span = "$element/text:span"; + $this->assertTrue($doc->elementExists($span)); + $this->assertEquals($txt, $doc->getElement($span)->nodeValue); } /** @@ -55,8 +263,66 @@ public function testPageBreak() $doc = TestHelperDOCX::getDocument($phpWord, 'ODText'); - $element = '/office:document-content/office:body/office:text/text:section/text:p[2]'; - $this->assertTrue($doc->elementExists($element, 'content.xml')); - $this->assertEquals('P1', $doc->getElementAttribute($element, 'text:style-name', 'content.xml')); + $element = '/office:document-content/office:body/office:text/text:section/text:p[3]'; + self::assertTrue($doc->elementExists($element, 'content.xml')); + self::assertEquals('PB', $doc->getElementAttribute($element, 'text:style-name', 'content.xml')); + } + + /** + * Test tracked changes + */ + public function testTrackedChanges() + { + $phpWord = new \PhpOffice\PhpWord\PhpWord(); + + // New portrait section + $section = $phpWord->addSection(); + $textRun = $section->addTextRun(); + + $text = $textRun->addText('Hello World! Time to '); + + $text = $textRun->addText('wake ', array('bold' => true)); + $text->setChangeInfo(TrackChange::INSERTED, 'Fred', time() - 1800); + + $text = $textRun->addText('up'); + $text->setTrackChange(new TrackChange(TrackChange::INSERTED, 'Fred')); + + $text = $textRun->addText('go to sleep'); + $text->setChangeInfo(TrackChange::DELETED, 'Barney', new \DateTime('@' . (time() - 3600))); + + $doc = TestHelperDOCX::getDocument($phpWord, 'ODText'); + + $tcs = '/office:document-content/office:body/office:text/text:tracked-changes'; + $tc1 = "$tcs/text:changed-region[1]"; + $tc1id = $doc->getElementAttribute($tc1, 'text:id'); + $element = "$tc1/text:insertion"; + self::assertTrue($doc->elementExists($element)); + $element .= '/office:change-info'; + self::AssertEquals('Fred', $doc->getElement("$element/dc:creator")->nodeValue); + self::assertTrue($doc->elementExists("$element/dc:date")); + + $tc2 = "$tcs/text:changed-region[2]"; + $tc2id = $doc->getElementAttribute($tc2, 'text:id'); + $element = "$tc2/text:insertion"; + self::assertTrue($doc->elementExists($element)); + $element .= '/office:change-info'; + self::AssertEquals('Fred', $doc->getElement("$element/dc:creator")->nodeValue); + //self::assertTrue($doc->elementExists("$element/dc:date")); + + $tc3 = "$tcs/text:changed-region[3]"; + $tc3id = $doc->getElementAttribute($tc3, 'text:id'); + $element = "$tc3/text:deletion"; + self::assertTrue($doc->elementExists($element)); + $element .= '/office:change-info'; + self::AssertEquals('Barney', $doc->getElement("$element/dc:creator")->nodeValue); + self::assertTrue($doc->elementExists("$element/dc:date")); + + $p2t = '/office:document-content/office:body/office:text/text:section/text:p[2]'; + $element = "$p2t/text:span[2]/text:change-start"; + self::AssertEquals($tc1id, $doc->getElementAttribute($element, 'text:change-id')); + $element = "$p2t/text:span[3]/text:change-start"; + self::AssertEquals($tc2id, $doc->getElementAttribute($element, 'text:change-id')); + $element = "$p2t/text:change"; + self::AssertEquals($tc3id, $doc->getElementAttribute($element, 'text:change-id')); } } diff --git a/tests/PhpWord/Writer/ODText/Part/AbstractPartTest.php b/tests/PhpWord/Writer/ODText/Part/AbstractPartTest.php index 51d893d23e..3f0c81293d 100644 --- a/tests/PhpWord/Writer/ODText/Part/AbstractPartTest.php +++ b/tests/PhpWord/Writer/ODText/Part/AbstractPartTest.php @@ -23,7 +23,6 @@ * Test class for PhpOffice\PhpWord\Writer\ODText\Part\AbstractPart * * @coversDefaultClass \PhpOffice\PhpWord\Writer\ODText\Part\AbstractPart - * @runTestsInSeparateProcesses */ class AbstractPartTest extends \PHPUnit\Framework\TestCase { diff --git a/tests/PhpWord/Writer/ODText/Part/ContentTest.php b/tests/PhpWord/Writer/ODText/Part/ContentTest.php index 2e501c6024..55d1a00e7f 100644 --- a/tests/PhpWord/Writer/ODText/Part/ContentTest.php +++ b/tests/PhpWord/Writer/ODText/Part/ContentTest.php @@ -25,7 +25,6 @@ * Test class for PhpOffice\PhpWord\Writer\ODText\Part\Content * * @coversDefaultClass \PhpOffice\PhpWord\Writer\ODText\Part\Content - * @runTestsInSeparateProcesses */ class ContentTest extends \PHPUnit\Framework\TestCase { @@ -92,7 +91,7 @@ public function testWriteContent() $doc = TestHelperDOCX::getDocument($phpWord, 'ODText'); - $element = '/office:document-content/office:body/office:text/text:section/text:p'; + $element = '/office:document-content/office:body/office:text/text:section/text:p[2]'; $this->assertEquals($expected, $doc->getElement($element, 'content.xml')->nodeValue); } diff --git a/tests/PhpWord/Writer/ODText/Style/FontTest.php b/tests/PhpWord/Writer/ODText/Style/FontTest.php new file mode 100644 index 0000000000..22a7151c98 --- /dev/null +++ b/tests/PhpWord/Writer/ODText/Style/FontTest.php @@ -0,0 +1,252 @@ +addSection(); + $section->addText('This is red (800) in rtf/html, default in docx/odt', array('color' => '800')); + $section->addText('This should be cyanish (008787)', array('color' => '008787')); + $section->addText('This should be dark green (FGCOLOR_DARKGREEN)', array('color' => \PhpOffice\PhpWord\Style\Font::FGCOLOR_DARKGREEN)); + $section->addText('This color is default (unknow)', array('color' => 'unknow')); + + $doc = TestHelperDOCX::getDocument($phpWord, 'ODText'); + $s2a = '/office:document-content/office:automatic-styles'; + $this->assertTrue($doc->elementExists($s2a)); + $s2t = '/office:document-content/office:body/office:text/text:section'; + $this->assertTrue($doc->elementExists($s2t)); + + $element = "$s2a/style:style[5]"; + $this->assertTrue($doc->elementExists($element)); + $style = $doc->getElementAttribute($element, 'style:name'); + $element .= '/style:text-properties'; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('#008787', $doc->getElementAttribute($element, 'fo:color')); + $span = "$s2t/text:p[3]/text:span"; + $this->assertTrue($doc->elementExists($span)); + $this->assertEquals($style, $doc->getElementAttribute($span, 'text:style-name')); + $this->assertEquals('This should be cyanish (008787)', $doc->getElement($span)->nodeValue); + + $element = "$s2a/style:style[7]"; + $this->assertTrue($doc->elementExists($element)); + $style = $doc->getElementAttribute($element, 'style:name'); + $element .= '/style:text-properties'; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('#006400', $doc->getElementAttribute($element, 'fo:color')); + $span = "$s2t/text:p[4]/text:span"; + $this->assertTrue($doc->elementExists($span)); + $this->assertEquals($style, $doc->getElementAttribute($span, 'text:style-name')); + $this->assertEquals('This should be dark green (FGCOLOR_DARKGREEN)', $doc->getElement($span)->nodeValue); + } + + public function providerAllNamedColors() + { + return array( + array(Font::FGCOLOR_YELLOW, 'FFFF00'), + array(Font::FGCOLOR_LIGHTGREEN, '90EE90'), + array(Font::FGCOLOR_CYAN, '00FFFF'), + array(Font::FGCOLOR_MAGENTA, 'FF00FF'), + array(Font::FGCOLOR_BLUE, '0000FF'), + array(Font::FGCOLOR_RED, 'FF0000'), + array(Font::FGCOLOR_DARKBLUE, '00008B'), + array(Font::FGCOLOR_DARKCYAN, '008B8B'), + array(Font::FGCOLOR_DARKGREEN, '006400'), + array(Font::FGCOLOR_DARKMAGENTA, '8B008B'), + array(Font::FGCOLOR_DARKRED, '8B0000'), + array(Font::FGCOLOR_DARKYELLOW, '8B8B00'), + array(Font::FGCOLOR_DARKGRAY, 'A9A9A9'), + array(Font::FGCOLOR_LIGHTGRAY, 'D3D3D3'), + array(Font::FGCOLOR_BLACK, '000000'), + array('unknow', 'unknow'), + array('unknown', 'unknown'), + ); + } + + /** + * @dataProvider providerAllNamedColors + * + * @param string $namedColor + * @param string $rgbColor + */ + public function testAllNamedColors($namedColor, $rgbColor) + { + $phpWord = new \PhpOffice\PhpWord\PhpWord(); + $section = $phpWord->addSection(); + $section->addText('This is red (800) in rtf/html, default in docx/odt', array('color' => '800')); + $section->addText('This should be cyanish (008787)', array('color' => '008787')); + $section->addText($namedColor, array('color' => $namedColor)); + + $doc = TestHelperDOCX::getDocument($phpWord, 'ODText'); + $s2a = '/office:document-content/office:automatic-styles'; + $this->assertTrue($doc->elementExists($s2a)); + $s2t = '/office:document-content/office:body/office:text/text:section'; + $this->assertTrue($doc->elementExists($s2t)); + + $element = "$s2a/style:style[7]"; + $this->assertTrue($doc->elementExists($element)); + $style = $doc->getElementAttribute($element, 'style:name'); + $element .= '/style:text-properties'; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals("#$rgbColor", $doc->getElementAttribute($element, 'fo:color')); + $span = "$s2t/text:p[4]/text:span"; + $this->assertTrue($doc->elementExists($span)); + $this->assertEquals($style, $doc->getElementAttribute($span, 'text:style-name')); + $this->assertEquals($namedColor, $doc->getElement($span)->nodeValue); + } + + /** + * Test noproof + */ + public function testNoProof() + { + $phpWord = new \PhpOffice\PhpWord\PhpWord(); + $section = $phpWord->addSection(); + $section->addText('Noproof not specified', array('color' => 'black')); + $section->addText('Noproof is true', array('color' => 'black', 'noproof' => true)); + $section->addText('Noproof is false', array('color' => 'black', 'noproof' => false)); + + $doc = TestHelperDOCX::getDocument($phpWord, 'ODText'); + $s2a = '/office:document-content/office:automatic-styles'; + $this->assertTrue($doc->elementExists($s2a)); + $s2t = '/office:document-content/office:body/office:text/text:section'; + $this->assertTrue($doc->elementExists($s2t)); + + $element = "$s2a/style:style[3]"; + $this->assertTrue($doc->elementExists($element)); + $style = $doc->getElementAttribute($element, 'style:name'); + $element .= '/style:text-properties'; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('', $doc->getElementAttribute($element, 'fo:language')); + $span = "$s2t/text:p[2]/text:span"; + $this->assertTrue($doc->elementExists($span)); + $this->assertEquals($style, $doc->getElementAttribute($span, 'text:style-name')); + $this->assertEquals('Noproof not specified', $doc->getElement($span)->nodeValue); + + $element = "$s2a/style:style[5]"; + $this->assertTrue($doc->elementExists($element)); + $style = $doc->getElementAttribute($element, 'style:name'); + $element .= '/style:text-properties'; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('zxx', $doc->getElementAttribute($element, 'fo:language')); + $this->assertEquals('zxx', $doc->getElementAttribute($element, 'style:language-asian')); + $this->assertEquals('zxx', $doc->getElementAttribute($element, 'style:language-complex')); + $this->assertEquals('none', $doc->getElementAttribute($element, 'fo:country')); + $this->assertEquals('none', $doc->getElementAttribute($element, 'style:country-asian')); + $this->assertEquals('none', $doc->getElementAttribute($element, 'style:country-complex')); + $span = "$s2t/text:p[3]/text:span"; + $this->assertTrue($doc->elementExists($span)); + $this->assertEquals($style, $doc->getElementAttribute($span, 'text:style-name')); + $this->assertEquals('Noproof is true', $doc->getElement($span)->nodeValue); + + $element = "$s2a/style:style[7]"; + $this->assertTrue($doc->elementExists($element)); + $style = $doc->getElementAttribute($element, 'style:name'); + $element .= '/style:text-properties'; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('', $doc->getElementAttribute($element, 'fo:language')); + $span = "$s2t/text:p[4]/text:span"; + $this->assertTrue($doc->elementExists($span)); + $this->assertEquals($style, $doc->getElementAttribute($span, 'text:style-name')); + $this->assertEquals('Noproof is false', $doc->getElement($span)->nodeValue); + } + + /** + * Test using object with a name as font style for addText + */ + public function testNamedStyleAsObject() + { + $phpWord = new \PhpOffice\PhpWord\PhpWord(); + $named = $phpWord->addFontStyle('namedobject', array('color' => '008787')); + $section = $phpWord->addSection(); + $section->addText('Let us see what color we wind up with', $named); + + $doc = TestHelperDOCX::getDocument($phpWord, 'ODText'); + $s2t = '/office:document-content/office:body/office:text/text:section'; + $this->assertTrue($doc->elementExists($s2t)); + $element = "$s2t/text:p[2]/text:span"; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('namedobject', $doc->getElementAttribute($element, 'text:style-name')); + } + + /** + * Test supplying field font style as array or object or string + */ + public function testFieldStyles() + { + $phpWord = new \PhpOffice\PhpWord\PhpWord(); + $namedstyle = $phpWord->addFontStyle('namedstyle', array('color' => '800000')); + $section = $phpWord->addSection(); + $textrun = $section->addTextRun(); + $fld = $textrun->addField('DATE'); + $fld->setFontStyle('namedstyle'); + $textrun = $section->addTextRun(); + $fld = $textrun->addField('DATE'); + $fld->setFontStyle(array('color' => '008000')); + $textrun = $section->addTextRun(); + $fld = $textrun->addField('DATE'); + $font = new \PhpOffice\PhpWord\Style\Font(); + $font->setColor('000080'); + $fld->setFontStyle($font); + $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]"; + $this->assertEquals('T1', $doc->getElementAttribute($element, 'style:name')); + $this->assertEquals('#008000', $doc->getElementAttribute("$element/style:text-properties", 'fo:color')); + $element = "$s2a/style:style[7]"; + $this->assertEquals('T2', $doc->getElementAttribute($element, 'style:name')); + $this->assertEquals('#000080', $doc->getElementAttribute("$element/style:text-properties", 'fo:color')); + + $element = "$s2t/text:p[2]/text:span"; + $this->assertEquals('namedstyle', $doc->getElementAttribute($element, 'text:style-name')); + $this->assertTrue($doc->elementExists("$element/text:date")); + $element = "$s2t/text:p[3]/text:span"; + $this->assertEquals('T1', $doc->getElementAttribute($element, 'text:style-name')); + $this->assertTrue($doc->elementExists("$element/text:date")); + $element = "$s2t/text:p[4]/text:span"; + $this->assertEquals('T2', $doc->getElementAttribute($element, 'text:style-name')); + $this->assertTrue($doc->elementExists("$element/text:date")); + $element = "$s2t/text:p[5]/text:span"; + $this->assertEquals('namedstyle', $doc->getElementAttribute($element, 'text:style-name')); + } +} diff --git a/tests/PhpWord/Writer/ODText/Style/ParagraphTest.php b/tests/PhpWord/Writer/ODText/Style/ParagraphTest.php new file mode 100644 index 0000000000..9ddb5fe1c3 --- /dev/null +++ b/tests/PhpWord/Writer/ODText/Style/ParagraphTest.php @@ -0,0 +1,465 @@ +addSection(); + $section->addText('Text on first page'); + $section->addPageBreak(); + $section->addText('Text on second page'); + + $doc = TestHelperDOCX::getDocument($phpWord, 'ODText'); + + $s2a = '/office:document-content/office:automatic-styles'; + $element = "$s2a/style:style[1]"; + $this->assertEquals('PB', $doc->getElementAttribute($element, 'style:name')); + $element .= '/style:paragraph-properties'; + $this->assertEquals('page', $doc->getElementAttribute($element, 'fo:break-after')); + $this->assertEquals('0cm', $doc->getElementAttribute($element, 'fo:margin-top')); + $this->assertEquals('0cm', $doc->getElementAttribute($element, 'fo:margin-bottom')); + + $s2a = '/office:document-content/office:body/office:text/text:section'; + $element = "$s2a/text:p[3]"; + $this->assertEquals('PB', $doc->getElementAttribute($element, 'text:style-name')); + } + + /** + * Test normal/indent + */ + public function testNormalIndent() + { + $phpWord = new PhpWord(); + $cvt = Converter::INCH_TO_TWIP; + $indent1 = array('indentation' => array('left' => 0.50 * $cvt)); + $indent2 = array('indentation' => array('left' => 1.00 * $cvt, 'right' => 1.05 * $cvt)); + $indent3 = array('indentation' => array('left' => -0.50 * $cvt)); + $indent4 = array('indentation' => array('left' => 0 * $cvt)); + $phpWord->setDefaultParagraphStyle($indent1); + $section = $phpWord->addSection(); + $section->addText('Should use default indent (0.5)'); + $section->addText('Should use non-default indent (1.0) on both sides, and here\'s an extra long line to prove it', null, $indent2); + $section->addText('Should use non-default indent (-0.5)', null, $indent3); + $section->addText('Should use non-default indent (0)', null, $indent4); + + $doc = TestHelperDOCX::getDocument($phpWord, 'ODText'); + $s2a = '/office:document-content/office:automatic-styles'; + $this->assertTrue($doc->elementExists($s2a)); + + $element = "$s2a/style:style[4]"; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('Normal', $doc->getElementAttribute($element, 'style:parent-style-name')); + $element .= '/style:paragraph-properties'; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('', $doc->getElementAttribute($element, 'fo:margin-left')); + $this->assertEquals('', $doc->getElementAttribute($element, 'fo:margin-right')); + + $element = "$s2a/style:style[6]/style:paragraph-properties"; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('1in', $doc->getElementAttribute($element, 'fo:margin-left')); + $this->assertEquals('1.05in', $doc->getElementAttribute($element, 'fo:margin-right')); + + $element = "$s2a/style:style[8]/style:paragraph-properties"; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('-0.5in', $doc->getElementAttribute($element, 'fo:margin-left')); + $this->assertEquals('0in', $doc->getElementAttribute($element, 'fo:margin-right')); + + $element = "$s2a/style:style[10]/style:paragraph-properties"; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('0in', $doc->getElementAttribute($element, 'fo:margin-left')); + $this->assertEquals('0in', $doc->getElementAttribute($element, 'fo:margin-right')); + + $doc->setDefaultFile('styles.xml'); + $element = '/office:document-styles/office:styles/style:style'; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('Normal', $doc->getElementAttribute($element, 'style:name')); + $element .= '/style:paragraph-properties'; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('0.5in', $doc->getElementAttribute($element, 'fo:margin-left')); + $this->assertEquals('0in', $doc->getElementAttribute($element, 'fo:margin-right')); + } + + /** + * Test textAlign + */ + public function testTextAlign() + { + $phpWord = new PhpWord(); + $align1 = array('alignment' => 'end'); + $align2 = array('alignment' => 'start'); + $phpWord->setDefaultParagraphStyle($align1); + $section = $phpWord->addSection(); + $section->addText('Should use default alignment (right for this doc)'); + $section->addText('Explicit left alignment', null, $align2); + $section->addText('Explicit right alignment', null, $align1); + + $doc = TestHelperDOCX::getDocument($phpWord, 'ODText'); + $s2a = '/office:document-content/office:automatic-styles'; + $this->assertTrue($doc->elementExists($s2a)); + + $element = "$s2a/style:style[4]"; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('Normal', $doc->getElementAttribute($element, 'style:parent-style-name')); + $element .= '/style:paragraph-properties'; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('', $doc->getElementAttribute($element, 'fo:text-align')); + + $element = "$s2a/style:style[6]/style:paragraph-properties"; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('start', $doc->getElementAttribute($element, 'fo:text-align')); + + $element = "$s2a/style:style[8]/style:paragraph-properties"; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('end', $doc->getElementAttribute($element, 'fo:text-align')); + + $doc->setDefaultFile('styles.xml'); + $element = '/office:document-styles/office:styles/style:style'; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('Normal', $doc->getElementAttribute($element, 'style:name')); + $element .= '/style:paragraph-properties'; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('end', $doc->getElementAttribute($element, 'fo:text-align')); + } + + /** + * Test lineHeight + */ + public function testLineHeight() + { + $phpWord = new PhpWord(); + $section = $phpWord->addSection(); + $section->addText('Should use line height 1.08, and here\'s a long line which ought to overflow onto a second line to prove it', null, array('lineHeight' => 1.08)); + $section->addText('Should use line height 1.20, and here\'s a long line which ought to overflow onto a second line to prove it', null, array('lineHeight' => 1.20)); + $section->addText('Should use line height 0.90, and here\'s a long line which ought to overflow onto a second line to prove it', null, array('lineHeight' => 0.90)); + + $doc = TestHelperDOCX::getDocument($phpWord, 'ODText'); + $s2a = '/office:document-content/office:automatic-styles'; + $this->assertTrue($doc->elementExists($s2a)); + + $element = "$s2a/style:style[4]/style:paragraph-properties"; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('108%', $doc->getElementAttribute($element, 'fo:line-height')); + + $element = "$s2a/style:style[6]/style:paragraph-properties"; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('120%', $doc->getElementAttribute($element, 'fo:line-height')); + + $element = "$s2a/style:style[8]/style:paragraph-properties"; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('90%', $doc->getElementAttribute($element, 'fo:line-height')); + } + + /** + * Test SpaceBeforeAfter + */ + public function testSpaceBeforeAfter() + { + $phpWord = new PhpWord(); + $phpWord->setDefaultParagraphStyle(array('spaceBefore' => 0, 'spaceAfter' => 0)); + $section = $phpWord->addSection(); + $section->addText('No spacing between this paragraph and next'); + $section->addText('No spacing between this paragraph and previous'); + $section->addText('No spacing before this but 100 after', null, array('spaceAfter' => 100)); + $section->addText('No spacing for this paragraph but previous specified 100 after and next specifies 100 before'); + $section->addText('No spacing after this but 100 before', null, array('spaceBefore' => 100)); + $section->addText('No spacing before this paragraph'); + + $doc = TestHelperDOCX::getDocument($phpWord, 'ODText'); + $s2a = '/office:document-content/office:automatic-styles'; + $this->assertTrue($doc->elementExists($s2a)); + + $element = "$s2a/style:style[8]/style:paragraph-properties"; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('', $doc->getElementAttribute($element, 'fo:margin-top')); + $this->assertEquals('5pt', $doc->getElementAttribute($element, 'fo:margin-bottom')); + + $element = "$s2a/style:style[12]/style:paragraph-properties"; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('5pt', $doc->getElementAttribute($element, 'fo:margin-top')); + $this->assertEquals('', $doc->getElementAttribute($element, 'fo:margin-bottom')); + + $doc->setDefaultFile('styles.xml'); + $element = '/office:document-styles/office:styles/style:style'; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('Normal', $doc->getElementAttribute($element, 'style:name')); + $element .= '/style:paragraph-properties'; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('0pt', $doc->getElementAttribute($element, 'fo:margin-top')); + $this->assertEquals('0pt', $doc->getElementAttribute($element, 'fo:margin-bottom')); + } + + /** + * Test Page Break Before + */ + public function testPageBreakBefore() + { + $phpWord = new PhpWord(); + $section = $phpWord->addSection(); + $section->addText('This is my first paragraph.'); + $section->addText('This is my second paragraph, on a new page.', null, array('pageBreakBefore' => true)); + $section->addText('This is my third paragraph, on same page as second.'); + $section->addText('This is my fourth paragraph, on a new page.', null, array('pageBreakBefore' => true)); + + $doc = TestHelperDOCX::getDocument($phpWord, 'ODText'); + $s2a = '/office:document-content/office:automatic-styles'; + $this->assertTrue($doc->elementExists($s2a)); + + $element = "$s2a/style:style[4]/style:paragraph-properties"; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('', $doc->getElementAttribute($element, 'fo:break-before')); + $element = "$s2a/style:style[6]/style:paragraph-properties"; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('page', $doc->getElementAttribute($element, 'fo:break-before')); + $element = "$s2a/style:style[8]/style:paragraph-properties"; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('', $doc->getElementAttribute($element, 'fo:break-before')); + $element = "$s2a/style:style[10]/style:paragraph-properties"; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('page', $doc->getElementAttribute($element, 'fo:break-before')); + } + + /** + * Test Heading Page Break Before + */ + public function testHeadingPageBreakBefore() + { + $phpWord = new PhpWord(); + $phpWord->addTitleStyle(1, null, array('pageBreakBefore' => true)); + $phpWord->addTitleStyle(2, null, array()); + $section = $phpWord->addSection(); + $section->addTitle('Section1 Heading1 #1', 1); + $section->addTitle('Section1 Heading2 #1', 2); + $section->addTitle('Section1 Heading1 #2', 1); + $section->addTitle('Section1 Heading2 #2', 2); + $section = $phpWord->addSection(); + $section->addTitle('Section2 Heading1 #1', 1); + $section->addTitle('Section2 Heading2 #1', 2); + + $doc = TestHelperDOCX::getDocument($phpWord, 'ODText'); + $s2a = '/office:document-content/office:automatic-styles'; + $this->assertTrue($doc->elementExists($s2a)); + + $element = "$s2a/style:style[4]"; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('HD1', $doc->getElementAttribute($element, 'style:name')); + $this->assertEquals('Heading_1', $doc->getElementAttribute($element, 'style:parent-style-name')); + $element .= '/style:paragraph-properties'; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('page', $doc->getElementAttribute($element, 'fo:break-before')); + + $element = "$s2a/style:style[5]"; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('HE1', $doc->getElementAttribute($element, 'style:name')); + $this->assertEquals('Heading_1', $doc->getElementAttribute($element, 'style:parent-style-name')); + $element .= '/style:paragraph-properties'; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('auto', $doc->getElementAttribute($element, 'fo:break-before')); + + $element = "$s2a/style:style[6]"; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('HD2', $doc->getElementAttribute($element, 'style:name')); + $this->assertEquals('Heading_2', $doc->getElementAttribute($element, 'style:parent-style-name')); + $element .= '/style:paragraph-properties'; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('', $doc->getElementAttribute($element, 'fo:break-before')); + + $element = "$s2a/style:style[7]"; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('HE2', $doc->getElementAttribute($element, 'style:name')); + $this->assertEquals('Heading_2', $doc->getElementAttribute($element, 'style:parent-style-name')); + $element .= '/style:paragraph-properties'; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('auto', $doc->getElementAttribute($element, 'fo:break-before')); + + $s2a = '/office:document-content/office:body/office:text/text:section[1]'; + $this->assertTrue($doc->elementExists($s2a)); + $element = "$s2a/text:h[1]"; + $this->assertEquals('HE1', $doc->getElementAttribute($element, 'text:style-name')); + $this->assertEquals('1', $doc->getElementAttribute($element, 'text:outline-level')); + $element .= '/text:span'; + $this->assertEquals('Heading_1', $doc->getElementAttribute($element, 'text:style-name')); + $element = "$s2a/text:h[2]"; + $this->assertEquals('HD2', $doc->getElementAttribute($element, 'text:style-name')); + $this->assertEquals('2', $doc->getElementAttribute($element, 'text:outline-level')); + $element .= '/text:span'; + $this->assertEquals('Heading_2', $doc->getElementAttribute($element, 'text:style-name')); + $element = "$s2a/text:h[3]"; + $this->assertEquals('HD1', $doc->getElementAttribute($element, 'text:style-name')); + $this->assertEquals('1', $doc->getElementAttribute($element, 'text:outline-level')); + $element .= '/text:span'; + $this->assertEquals('Heading_1', $doc->getElementAttribute($element, 'text:style-name')); + $element = "$s2a/text:h[4]"; + $this->assertEquals('HD2', $doc->getElementAttribute($element, 'text:style-name')); + $this->assertEquals('2', $doc->getElementAttribute($element, 'text:outline-level')); + $element .= '/text:span'; + $this->assertEquals('Heading_2', $doc->getElementAttribute($element, 'text:style-name')); + + $s2a = '/office:document-content/office:body/office:text/text:section[2]'; + $this->assertTrue($doc->elementExists($s2a)); + $element = "$s2a/text:h[1]"; + $this->assertEquals('HE1', $doc->getElementAttribute($element, 'text:style-name')); + $this->assertEquals('1', $doc->getElementAttribute($element, 'text:outline-level')); + $element .= '/text:span'; + $this->assertEquals('Heading_1', $doc->getElementAttribute($element, 'text:style-name')); + $element = "$s2a/text:h[2]"; + $this->assertEquals('HD2', $doc->getElementAttribute($element, 'text:style-name')); + $this->assertEquals('2', $doc->getElementAttribute($element, 'text:outline-level')); + $element .= '/text:span'; + $this->assertEquals('Heading_2', $doc->getElementAttribute($element, 'text:style-name')); + + $doc->setDefaultFile('styles.xml'); + $s2a = '/office:document-styles/office:styles'; + $this->assertTrue($doc->elementExists($s2a)); + $element = "$s2a/style:style[1]"; + $this->assertEquals('Heading_1', $doc->getElementAttribute($element, 'style:name')); + $this->assertEquals('paragraph', $doc->getElementAttribute($element, 'style:family')); + $element .= '/style:paragraph-properties'; + $this->assertEquals('page', $doc->getElementAttribute($element, 'fo:break-before')); + $element = "$s2a/style:style[3]"; + $this->assertEquals('Heading_2', $doc->getElementAttribute($element, 'style:name')); + $this->assertEquals('paragraph', $doc->getElementAttribute($element, 'style:family')); + $element .= '/style:paragraph-properties'; + $this->assertEquals('', $doc->getElementAttribute($element, 'fo:break-before')); + } + + /** + * Test text run paragraph style using named style + */ + public function testTextRun() + { + $phpWord = new \PhpOffice\PhpWord\PhpWord(); + $phpWord->addParagraphStyle('parstyle1', array('align' => 'start')); + $phpWord->addParagraphStyle('parstyle2', array('align' => 'end')); + $section = $phpWord->addSection(); + $trx = $section->addTextRun('parstyle1'); + $trx->addText('First text in textrun. '); + $trx->addText('Second text - paragraph style is specified but ignored.', null, 'parstyle2'); + $section->addText('Third text added to section not textrun - paragraph style is specified and used.', null, 'parstyle2'); + + $doc = TestHelperDOCX::getDocument($phpWord, 'ODText'); + $s2a = '/office:document-content/office:automatic-styles'; + $element = "$s2a/style:style[3]"; + $this->assertEquals('P1_parstyle1', $doc->getElementAttribute($element, 'style:name')); + $this->assertEquals('parstyle1', $doc->getElementAttribute($element, 'style:parent-style-name')); + $element = "$s2a/style:style[9]"; + $this->assertEquals('P4_parstyle2', $doc->getElementAttribute($element, 'style:name')); + $this->assertEquals('parstyle2', $doc->getElementAttribute($element, 'style:parent-style-name')); + + $s2a = '/office:document-content/office:body/office:text/text:section'; + $element = "$s2a/text:p[2]"; + $this->assertEquals('P1_parstyle1', $doc->getElementAttribute($element, 'text:style-name')); + $element = "$s2a/text:p[3]"; + $this->assertEquals('P4_parstyle2', $doc->getElementAttribute($element, 'text:style-name')); + + $doc->setDefaultFile('styles.xml'); + $element = '/office:document-styles/office:styles/style:style[1]'; + $this->assertEquals('parstyle1', $doc->getElementAttribute($element, 'style:name')); + $element .= '/style:paragraph-properties'; + $this->assertEquals('start', $doc->getElementAttribute($element, 'fo:text-align')); + $element = '/office:document-styles/office:styles/style:style[2]'; + $this->assertEquals('parstyle2', $doc->getElementAttribute($element, 'style:name')); + $element .= '/style:paragraph-properties'; + $this->assertEquals('end', $doc->getElementAttribute($element, 'fo:text-align')); + } + + /** + * Test text run paragraph style using unnamed style + */ + public function testTextRunUnnamed() + { + $phpWord = new \PhpOffice\PhpWord\PhpWord(); + $parstyle1 = array('align' => 'start'); + $parstyle2 = array('align' => 'end'); + $section = $phpWord->addSection(); + $trx = $section->addTextRun($parstyle1); + $trx->addText('First text in textrun. '); + $trx->addText('Second text - paragraph style is specified but ignored.', null, $parstyle2); + $section->addText('Third text added to section not textrun - paragraph style is specified and used.', null, $parstyle2); + + $doc = TestHelperDOCX::getDocument($phpWord, 'ODText'); + $s2a = '/office:document-content/office:automatic-styles'; + $element = "$s2a/style:style[3]"; + $this->assertEquals('P1', $doc->getElementAttribute($element, 'style:name')); + $this->assertEquals('Normal', $doc->getElementAttribute($element, 'style:parent-style-name')); + $element .= '/style:paragraph-properties'; + $this->assertEquals('start', $doc->getElementAttribute($element, 'fo:text-align')); + $element = "$s2a/style:style[9]"; + $this->assertEquals('P4', $doc->getElementAttribute($element, 'style:name')); + $this->assertEquals('Normal', $doc->getElementAttribute($element, 'style:parent-style-name')); + $element .= '/style:paragraph-properties'; + $this->assertEquals('end', $doc->getElementAttribute($element, 'fo:text-align')); + + $s2a = '/office:document-content/office:body/office:text/text:section'; + $element = "$s2a/text:p[2]"; + $this->assertEquals('P1', $doc->getElementAttribute($element, 'text:style-name')); + $element = "$s2a/text:p[3]"; + $this->assertEquals('P4', $doc->getElementAttribute($element, 'text:style-name')); + } + + /** + * Test Empty font and paragraph styles + */ + public function testEmptyFontAndParagraphStyles() + { + $phpWord = new \PhpOffice\PhpWord\PhpWord(); + $section = $phpWord->addSection(); + $phpWord->addFontStyle('namedfont', array('name' => 'Courier New', 'size' => 8)); + $phpWord->addParagraphStyle('namedpar', array('lineHeight' => 1.08)); + $section->addText('Empty Font Style and Empty Paragraph Style', '', ''); + $section->addText('Named Font Style and Empty Paragraph Style', 'namedfont', ''); + $section->addText('Empty Font Style and Named Paragraph Style', '', 'namedpar'); + $section->addText('Named Font Style and Named Paragraph Style', 'namedfont', 'namedpar'); + + $doc = TestHelperDOCX::getDocument($phpWord, 'ODText'); + $s2a = '/office:document-content/office:body/office:text/text:section'; + $element = "$s2a/text:p[2]"; + $this->assertEquals('Normal', $doc->getElementAttribute($element, 'text:style-name')); + $this->assertEquals(5, $doc->getElementAttribute("$element/text:s", 'text:c')); + $this->assertFalse($doc->elementExists("$element/text:span")); + $element = "$s2a/text:p[3]"; + $this->assertEquals('Normal', $doc->getElementAttribute($element, 'text:style-name')); + $this->assertEquals('namedfont', $doc->getElementAttribute("$element/text:span", 'text:style-name')); + $element = "$s2a/text:p[4]"; + $this->assertEquals('P1_namedpar', $doc->getElementAttribute($element, 'text:style-name')); + $this->assertFalse($doc->elementExists("$element/text:span")); + $element = "$s2a/text:p[5]"; + $this->assertEquals('P2_namedpar', $doc->getElementAttribute($element, 'text:style-name')); + $this->assertEquals('namedfont', $doc->getElementAttribute("$element/text:span", 'text:style-name')); + } +} diff --git a/tests/PhpWord/Writer/ODText/Style/SectionTest.php b/tests/PhpWord/Writer/ODText/Style/SectionTest.php new file mode 100644 index 0000000000..d471c7f0e1 --- /dev/null +++ b/tests/PhpWord/Writer/ODText/Style/SectionTest.php @@ -0,0 +1,249 @@ +addFontStyle('hdrstyle1', array('name' => 'Courier New', 'size' => 8)); + $section = $phpWord->addSection(array('paperSize' => 'Letter', 'marginTop' => $margins, 'marginBottom' => $margins)); + $header = $section->createHeader(); + $phpWord->addParagraphStyle('centerheader', array('align' => 'center')); + $header->addText('Centered Header', 'hdrstyle1', 'centerheader'); + $footer = $section->createFooter(); + $sizew = $section->getStyle()->getPageSizeW(); + $sizel = $section->getStyle()->getMarginLeft(); + $sizer = $section->getStyle()->getMarginRight(); + $footerwidth = $sizew - $sizel - $sizer; + $phpWord->addParagraphStyle( + 'footerTab', + array( + 'tabs' => array( + new \PhpOffice\PhpWord\Style\Tab('center', (int) ($footerwidth / 2)), + new \PhpOffice\PhpWord\Style\Tab('right', (int) $footerwidth), + ), + ) + ); + $textrun = $footer->addTextRun('footerTab'); + $textrun->addText('Left footer', 'hdrstyle1'); + $textrun->addText("\t", 'hdrstyle1'); + $fld = $textrun->addField('DATE'); + $fld->setFontStyle('hdrstyle1'); + $textrun->addText("\t", 'hdrstyle1'); + $textrun->addText('Page ', 'hdrstyle1'); + $fld = $textrun->addField('PAGE'); + $fld->setFontStyle('hdrstyle1'); + $textrun->addText(' of ', 'hdrstyle1'); + $fld = $textrun->addField('NUMPAGES'); + $fld->setFontStyle('hdrstyle1'); + $section->addText('First page'); + $section->addPageBreak(); + $section->addText('Second page'); + $section->addPageBreak(); + $section->addText('Third page'); + + $doc = TestHelperDOCX::getDocument($phpWord, 'ODText'); + $doc->setDefaultFile('styles.xml'); + $s2a = '/office:document-styles/office:automatic-styles'; + $element = "$s2a/style:page-layout/style:page-layout-properties"; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('8.5in', $doc->getElementAttribute($element, 'fo:page-width')); + $this->assertEquals('11in', $doc->getElementAttribute($element, 'fo:page-height')); + $this->assertEquals('0.5in', $doc->getElementAttribute($element, 'fo:margin-top')); + $this->assertEquals('0.5in', $doc->getElementAttribute($element, 'fo:margin-bottom')); + + $s2s = '/office:document-styles/office:styles'; + $element = "$s2s/style:style[1]"; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('hdrstyle1', $doc->getElementAttribute($element, 'style:name')); + $tprop = "$element/style:text-properties"; + $this->assertTrue($doc->elementExists($tprop)); + $this->assertEquals('Courier New', $doc->getElementAttribute($tprop, 'style:font-name')); + + $element = "$s2s/style:style[2]"; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('centerheader', $doc->getElementAttribute($element, 'style:name')); + $tprop = "$element/style:paragraph-properties"; + $this->assertTrue($doc->elementExists($tprop)); + $this->assertEquals('center', $doc->getElementAttribute($tprop, 'fo:text-align')); + + $element = "$s2s/style:style[3]"; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('footerTab', $doc->getElementAttribute($element, 'style:name')); + $tprop = "$element/style:paragraph-properties/style:tab-stops"; + $this->assertTrue($doc->elementExists($tprop)); + $tstop = "$tprop/style:tab-stop[1]"; + $this->assertTrue($doc->elementExists($tstop)); + $this->assertEquals('center', $doc->getElementAttribute($tstop, 'style:type')); + $this->assertEquals('3.25in', $doc->getElementAttribute($tstop, 'style:position')); + $tstop = "$tprop/style:tab-stop[2]"; + $this->assertTrue($doc->elementExists($tstop)); + $this->assertEquals('right', $doc->getElementAttribute($tstop, 'style:type')); + $this->assertEquals('6.5in', $doc->getElementAttribute($tstop, 'style:position')); + + $s2s = '/office:document-styles/office:master-styles/style:master-page/style:footer/text:p'; + $this->assertTrue($doc->elementExists($s2s)); + $element = "$s2s/text:span[1]"; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('hdrstyle1', $doc->getElementAttribute($element, 'text:style-name')); + $this->assertEquals('Left footer', $doc->getElement($element)->nodeValue); + $element = "$s2s/text:span[2]/text:tab"; + $this->assertTrue($doc->elementExists($element)); + $element = "$s2s/text:span[3]/text:date"; + $this->assertTrue($doc->elementExists($element)); + $element = "$s2s/text:span[4]/text:tab"; + $this->assertTrue($doc->elementExists($element)); + $element = "$s2s/text:span[5]"; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('Page', $doc->getElement($element)->nodeValue); + $this->assertTrue($doc->elementExists("$element/text:s")); + $element = "$s2s/text:span[6]/text:page-number"; + $this->assertTrue($doc->elementExists($element)); + $element = "$s2s/text:span[7]"; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('of', $doc->getElement($element)->nodeValue); + $this->assertTrue($doc->elementExists("$element/text:s")); + $this->assertTrue($doc->elementExists("$element/text:s[2]")); + $element = "$s2s/text:span[8]/text:page-count"; + $this->assertTrue($doc->elementExists($element)); + } + + /** + * Test HideErrors + */ + public function testHideErrors() + { + $phpWord = new PhpWord(); + $phpWord->getSettings()->setHideGrammaticalErrors(true); + $phpWord->getSettings()->setHideSpellingErrors(true); + $phpWord->getSettings()->setThemeFontLang(new \PhpOffice\PhpWord\Style\Language('en-US')); + $phpWord->getSettings()->getThemeFontLang()->setLangId(\PhpOffice\PhpWord\Style\Language::EN_US_ID); + $section = $phpWord->addSection(); + $section->addText('Here is a paragraph with some speling errorz'); + + $doc = TestHelperDOCX::getDocument($phpWord, 'ODText'); + $doc->setDefaultFile('styles.xml'); + $element = '/office:document-styles/office:styles/style:default-style/style:text-properties'; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('zxx', $doc->getElementAttribute($element, 'fo:language')); + $this->assertEquals('zxx', $doc->getElementAttribute($element, 'style:language-asian')); + $this->assertEquals('zxx', $doc->getElementAttribute($element, 'style:language-complex')); + $this->assertEquals('none', $doc->getElementAttribute($element, 'fo:country')); + $this->assertEquals('none', $doc->getElementAttribute($element, 'style:country-asian')); + $this->assertEquals('none', $doc->getElementAttribute($element, 'style:country-complex')); + } + + /** + * Test SpaceBeforeAfter + */ + public function testMultipleSections() + { + $phpWord = new PhpWord(); + $section = $phpWord->addSection(array('paperSize' => 'Letter', 'Orientation' => 'portrait')); + $section->addText('This section uses Letter paper in portrait orientation.'); + $section = $phpWord->addSection(array('paperSize' => 'A4', 'Orientation' => 'landscape', 'pageNumberingStart' => '9')); + $header = $section->createHeader(); + $header->addField('PAGE'); + $section->addText('This section uses A4 paper in landscape orientation. It should have a page break beforehand. It artificially starts on page 9.'); + + $doc = TestHelperDOCX::getDocument($phpWord, 'ODText'); + $s2a = '/office:document-content/office:automatic-styles'; + $s2t = '/office:document-content/office:body/office:text'; + $this->assertTrue($doc->elementExists($s2a)); + $this->assertTrue($doc->elementExists($s2t)); + + $element = "$s2a/style:style[2]"; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('SB1', $doc->getElementAttribute($element, 'style:name')); + $this->assertEquals('Standard1', $doc->getElementAttribute($element, 'style:master-page-name')); + $element .= '/style:text-properties'; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('none', $doc->getElementAttribute($element, 'text:display')); + $element = "$s2a/style:style[3]"; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('SB2', $doc->getElementAttribute($element, 'style:name')); + $this->assertEquals('Standard2', $doc->getElementAttribute($element, 'style:master-page-name')); + $elemen2 = "$element/style:paragraph-properties"; + $this->assertEquals('9', $doc->getElementAttribute($elemen2, 'style:page-number')); + $element .= '/style:text-properties'; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('none', $doc->getElementAttribute($element, 'text:display')); + + $element = "$s2t/text:section[1]"; + $this->assertTrue($doc->elementExists($element)); + $element .= '/text:p[1]'; + $this->assertEquals('SB1', $doc->getElementAttribute($element, 'text:style-name')); + $element = "$s2t/text:section[2]"; + $this->assertTrue($doc->elementExists($element)); + $element .= '/text:p[1]'; + $this->assertEquals('SB2', $doc->getElementAttribute($element, 'text:style-name')); + + $doc->setDefaultFile('styles.xml'); + $s2a = '/office:document-styles/office:automatic-styles'; + $this->assertTrue($doc->elementExists($s2a)); + + $element = "$s2a/style:page-layout[1]"; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('Mpm1', $doc->getElementAttribute($element, 'style:name')); + $element .= '/style:page-layout-properties'; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('8.5in', $doc->getElementAttribute($element, 'fo:page-width')); + $this->assertEquals('11in', $doc->getElementAttribute($element, 'fo:page-height')); + $this->assertEquals('portrait', $doc->getElementAttribute($element, 'style:print-orientation')); + + $element = "$s2a/style:page-layout[2]"; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('Mpm2', $doc->getElementAttribute($element, 'style:name')); + $element .= '/style:page-layout-properties'; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('29.7cm', $doc->getElementAttribute($element, 'fo:page-width')); + $this->assertEquals('21cm', $doc->getElementAttribute($element, 'fo:page-height')); + $this->assertEquals('landscape', $doc->getElementAttribute($element, 'style:print-orientation')); + + $s2a = '/office:document-styles/office:master-styles'; + $this->assertTrue($doc->elementExists($s2a)); + $element = "$s2a/style:master-page[1]"; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('Standard1', $doc->getElementAttribute($element, 'style:name')); + $this->assertEquals('Mpm1', $doc->getElementAttribute($element, 'style:page-layout-name')); + $element = "$s2a/style:master-page[2]"; + $this->assertTrue($doc->elementExists($element)); + $this->assertEquals('Standard2', $doc->getElementAttribute($element, 'style:name')); + $this->assertEquals('Mpm2', $doc->getElementAttribute($element, 'style:page-layout-name')); + } +} diff --git a/tests/PhpWord/Writer/ODText/StyleTest.php b/tests/PhpWord/Writer/ODText/StyleTest.php index b1bf417d59..bf8a3dd1f3 100644 --- a/tests/PhpWord/Writer/ODText/StyleTest.php +++ b/tests/PhpWord/Writer/ODText/StyleTest.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWord\Writer\ODText; -use PhpOffice\Common\XMLWriter; +use PhpOffice\PhpWord\Shared\XMLWriter; /** * Test class for PhpOffice\PhpWord\Writer\ODText\Style subnamespace diff --git a/tests/PhpWord/Writer/PDF/TCPDFTest.php b/tests/PhpWord/Writer/PDF/TCPDFTest.php index 6dc8f24cb7..53e55ca0b6 100644 --- a/tests/PhpWord/Writer/PDF/TCPDFTest.php +++ b/tests/PhpWord/Writer/PDF/TCPDFTest.php @@ -33,6 +33,18 @@ class TCPDFTest extends \PHPUnit\Framework\TestCase */ public function testConstruct() { + // TCPDF version 6.3.5 doesn't support PHP 5.3, fixed via https://github.com/tecnickcom/TCPDF/pull/197, + // pending new release. + if (version_compare(PHP_VERSION, '5.4.0', '<')) { + return; + } + + // TCPDF version 6.3.5 doesn't support PHP 8.0, fixed via https://github.com/tecnickcom/TCPDF/pull/293, + // pending new release. + if (version_compare(PHP_VERSION, '8.0.0', '>=')) { + return; + } + $file = __DIR__ . '/../../_files/tcpdf.pdf'; $phpWord = new PhpWord(); diff --git a/tests/PhpWord/Writer/Word2007/Element/ChartTest.php b/tests/PhpWord/Writer/Word2007/Element/ChartTest.php new file mode 100644 index 0000000000..432d8db86a --- /dev/null +++ b/tests/PhpWord/Writer/Word2007/Element/ChartTest.php @@ -0,0 +1,241 @@ +outputEscapingEnabled = Settings::isOutputEscapingEnabled(); + } + + /** + * Executed after each method of the class + */ + public function tearDown() + { + Settings::setOutputEscapingEnabled($this->outputEscapingEnabled); + TestHelperDOCX::clear(); + } + + /** + * Test chart elements + */ + public function testChartElements() + { + $phpWord = new PhpWord(); + $section = $phpWord->addSection(); + $style = array( + 'width' => 5000000, + 'height' => 5000000, + 'showAxisLabels' => true, + 'showGridX' => true, + 'showGridY' => true, + 'showLegend' => false, + ); + + $chartTypes = array('pie', 'doughnut', 'bar', 'line', 'area', 'scatter', 'radar'); + $categories = array('A', 'B', 'C', 'D', 'E'); + $series1 = array(1, 3, 2, 5, 4); + foreach ($chartTypes as $chartType) { + $section->addChart($chartType, $categories, $series1, $style); + } + $colorArray = array('FFFFFF', '000000', 'FF0000', '00FF00', '0000FF'); + $numColor = count($colorArray); + $chart = $section->addChart('pie', $categories, $series1, $style); + $chart->getStyle()->setColors($colorArray)->setTitle('3d chart')->set3d(true); + $chart = $section->addChart('stacked_bar', $categories, $series1, $style); + $chart->getStyle()->setColors($colorArray)->setShowLegend(true); + $chart = $section->addChart('scatter', $categories, $series1, $style); + $chart->getStyle()->setMajorTickPosition('cross'); + $section->addChart('scatter', $categories, $series1, $style, 'seriesname'); + + $doc = TestHelperDOCX::getDocument($phpWord); + + $index = 0; + foreach ($chartTypes as $chartType) { + ++$index; + $file = "word/charts/chart{$index}.xml"; + $path = "/c:chartSpace/c:chart/c:plotArea/c:{$chartType}Chart"; + self::assertTrue($doc->elementExists($path, $file), "chart type $chartType"); + } + + $index = 11; + $file = "word/charts/chart{$index}.xml"; + $doc->setDefaultFile($file); + $chartType = 'scatter'; + $path = "/c:chartSpace/c:chart/c:plotArea/c:{$chartType}Chart"; + self::assertEquals('seriesname', $doc->getElement($path . '/c:ser/c:tx/c:strRef/c:strCache/c:pt/c:v')->nodeValue); + + $index = 8; + $file = "word/charts/chart{$index}.xml"; + $doc->setDefaultFile($file); + $chartType = 'pie3D'; + $path = "/c:chartSpace/c:chart/c:plotArea/c:{$chartType}Chart"; + for ($idx = 0; $idx < $numColor; ++$idx) { + $idxp1 = $idx + 1; + $element = $path . "/c:ser/c:dPt[$idxp1]/c:spPr/a:solidFill/a:srgbClr"; + self::assertEquals($colorArray[$idx], $doc->getElementAttribute($element, 'val'), "pie3d chart idx=$idx"); + } + + $index = 9; + $file = "word/charts/chart{$index}.xml"; + $doc->setDefaultFile($file); + $chartType = 'bar'; + $path = "/c:chartSpace/c:chart/c:plotArea/c:{$chartType}Chart"; + for ($idxp1 = 1; $idxp1 < $numColor; ++$idxp1) { + $idx = $idxp1; // stacked bar chart is shifted + $element = $path . "/c:ser/c:dPt[$idxp1]/c:spPr/a:solidFill/a:srgbClr"; + self::assertEquals($colorArray[$idx], $doc->getElementAttribute($element, 'val'), "bar chart idx=$idx"); + } + } + + public function testChartEscapingEnabled() + { + Settings::setOutputEscapingEnabled(true); + $phpWord = new PhpWord(); + $section = $phpWord->addSection(); + $style = array( + 'width' => 5000000, + 'height' => 5000000, + 'showAxisLabels' => true, + 'showGridX' => true, + 'showGridY' => true, + 'showLegend' => false, + 'valueAxisTitle' => 'Values', + ); + $categories = array('A&B', 'C', 'E', 'F', 'G'); + $series1 = array(1, 3, 2, 5, 4); + $section->addChart('bar', $categories, $series1, $style); + $doc = TestHelperDOCX::getDocument($phpWord); + + $index = 1; + $file = "word/charts/chart{$index}.xml"; + $doc->setDefaultFile($file); + $chartType = 'bar'; + $path = "/c:chartSpace/c:chart/c:plotArea/c:{$chartType}Chart/c:ser/c:cat/c:strLit"; + $element = "$path/c:pt[1]/c:v"; + self::assertEquals('A&B', $doc->getElement($element)->nodeValue); + $element = "$path/c:pt[2]/c:v"; + self::assertEquals('C', $doc->getElement($element)->nodeValue); + } + + public function testChartEscapingDisabled() + { + Settings::setOutputEscapingEnabled(false); + $phpWord = new PhpWord(); + $section = $phpWord->addSection(); + $style = array( + 'width' => 5000000, + 'height' => 5000000, + 'showAxisLabels' => true, + 'showGridX' => true, + 'showGridY' => true, + 'showLegend' => false, + 'valueAxisTitle' => 'Values', + ); + $categories = array('A&B', 'C<D>', 'E', 'F', 'G'); + $series1 = array(1, 3, 2, 5, 4); + $section->addChart('bar', $categories, $series1, $style); + $doc = TestHelperDOCX::getDocument($phpWord); + + $index = 1; + $file = "word/charts/chart{$index}.xml"; + $doc->setDefaultFile($file); + $chartType = 'bar'; + $path = "/c:chartSpace/c:chart/c:plotArea/c:{$chartType}Chart/c:ser/c:cat/c:strLit"; + $element = "$path/c:pt[1]/c:v"; + self::assertEquals('A&B', $doc->getElement($element)->nodeValue); + $element = "$path/c:pt[2]/c:v"; + self::assertEquals('C', $doc->getElement($element)->nodeValue); + } + + public function testValueAxisTitle() + { + $phpWord = new PhpWord(); + $section = $phpWord->addSection(); + $style = array( + 'width' => 5000000, + 'height' => 5000000, + 'showAxisLabels' => true, + 'showGridX' => true, + 'showGridY' => true, + 'showLegend' => false, + 'valueAxisTitle' => 'Values', + ); + $chartType = 'line'; + $categories = array('A', 'B', 'C', 'D', 'E'); + $series1 = array(1, 3, 2, 5, 4); + $section->addChart($chartType, $categories, $series1, $style); + $doc = TestHelperDOCX::getDocument($phpWord); + + $index = 1; + $file = "word/charts/chart{$index}.xml"; + $doc->setDefaultFile($file); + $chartType = 'line'; + $path = '/c:chartSpace/c:chart/c:plotArea'; + $element = "$path/c:{$chartType}Chart"; + self::assertTrue($doc->elementExists($path)); + $element = "$path/c:valAx"; + self::assertTrue($doc->elementExists($element)); + $element .= '/c:title/c:tx/c:rich/a:p/a:r/a:t'; + self::assertEquals('Values', $doc->getElement($element)->nodeValue); + } + + public function testNoAxisLabels() + { + $phpWord = new PhpWord(); + $section = $phpWord->addSection(); + $style = array( + 'width' => 5000000, + 'height' => 5000000, + 'showAxisLabels' => false, + 'showGridX' => true, + 'showGridY' => true, + 'showLegend' => false, + 'valueAxisTitle' => 'Values', + ); + $chartType = 'line'; + $categories = array('A', 'B', 'C', 'D', 'E'); + $series1 = array(1, 3, 2, 5, 4); + $section->addChart($chartType, $categories, $series1, $style); + $doc = TestHelperDOCX::getDocument($phpWord); + + $index = 1; + $file = "word/charts/chart{$index}.xml"; + $doc->setDefaultFile($file); + $chartType = 'line'; + $path = '/c:chartSpace/c:chart/c:plotArea'; + $element = "$path/c:{$chartType}Chart"; + $element = "$path/c:valAx"; + $element .= '/c:tickLblPos'; + self::assertEquals('none', $doc->getElementAttribute($element, 'val')); + } +} diff --git a/tests/PhpWord/Writer/Word2007/Element/FormFieldTest.php b/tests/PhpWord/Writer/Word2007/Element/FormFieldTest.php new file mode 100644 index 0000000000..f3ee179037 --- /dev/null +++ b/tests/PhpWord/Writer/Word2007/Element/FormFieldTest.php @@ -0,0 +1,70 @@ +addSection(); + + $section->addFormField('textinput')->setName('MyTextBox'); + $section->addFormField('checkbox')->setDefault(true)->setValue('Your name'); + $section->addFormField('checkbox')->setDefault(true); + $section->addFormField('dropdown')->setEntries(array('Choice 1', 'Choice 2', 'Choice 3', '')); + + $doc = TestHelperDOCX::getDocument($phpWord); + + $path = '/w:document/w:body/w:p[1]/w:r/w:fldChar/w:ffData'; + $this->assertTrue($doc->elementExists("$path/w:textInput")); + $this->assertEquals('MyTextBox', $doc->getElementAttribute("$path/w:name", 'w:val')); + + $path = '/w:document/w:body/w:p[2]/w:r/w:fldChar/w:ffData'; + $this->assertTrue($doc->elementExists("$path/w:checkBox")); + $path = '/w:document/w:body/w:p[2]/w:r[4]/w:t'; + $this->assertEquals('Your name', $doc->getElement($path)->textContent); + + $path = '/w:document/w:body/w:p[3]/w:r/w:fldChar/w:ffData'; + $this->assertTrue($doc->elementExists("$path/w:checkBox")); + + $path = '/w:document/w:body/w:p[4]/w:r/w:fldChar/w:ffData/w:ddList'; + $this->assertTrue($doc->elementExists($path)); + $this->assertEquals('Choice 1', $doc->getElementAttribute("$path/w:listEntry[1]", 'w:val')); + $this->assertEquals('Choice 2', $doc->getElementAttribute("$path/w:listEntry[2]", 'w:val')); + $this->assertEquals('Choice 3', $doc->getElementAttribute("$path/w:listEntry[3]", 'w:val')); + $this->assertEquals('', trim($doc->getElementAttribute("$path/w:listEntry[4]", 'w:val'), ' ')); + } +} diff --git a/tests/PhpWord/Writer/Word2007/ElementTest.php b/tests/PhpWord/Writer/Word2007/ElementTest.php index e9c1ea5bd7..38b1ba75ab 100644 --- a/tests/PhpWord/Writer/Word2007/ElementTest.php +++ b/tests/PhpWord/Writer/Word2007/ElementTest.php @@ -17,11 +17,11 @@ namespace PhpOffice\PhpWord\Writer\Word2007; -use PhpOffice\Common\XMLWriter; use PhpOffice\PhpWord\Element\Comment; use PhpOffice\PhpWord\Element\TextRun; use PhpOffice\PhpWord\Element\TrackChange; use PhpOffice\PhpWord\PhpWord; +use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\TestHelperDOCX; /** @@ -249,33 +249,7 @@ public function testShapeElements() } } - /** - * Test shape elements - */ - public function testChartElements() - { - $phpWord = new PhpWord(); - $section = $phpWord->addSection(); - $style = array('width' => 1000000, 'height' => 1000000, 'showAxisLabels' => true, 'showGridX' => true, 'showGridY' => true); - - $chartTypes = array('pie', 'doughnut', 'bar', 'line', 'area', 'scatter', 'radar'); - $categories = array('A', 'B', 'C', 'D', 'E'); - $series1 = array(1, 3, 2, 5, 4); - foreach ($chartTypes as $chartType) { - $section->addChart($chartType, $categories, $series1, $style); - } - $section->addChart('pie', $categories, $series1, array('3d' => true)); - - $doc = TestHelperDOCX::getDocument($phpWord); - - $index = 0; - foreach ($chartTypes as $chartType) { - ++$index; - $file = "word/charts/chart{$index}.xml"; - $path = "/c:chartSpace/c:chart/c:plotArea/c:{$chartType}Chart"; - $this->assertTrue($doc->elementExists($path, $file)); - } - } + // testChartElements moved to Writer/Word2007/Element/ChartTest public function testFieldElement() { @@ -389,27 +363,7 @@ public function testMacroButtonField() $this->assertEquals(' MACROBUTTON Zoom100 double click to zoom ', $doc->getElement($element)->textContent); } - /** - * Test form fields - */ - public function testFormFieldElements() - { - $phpWord = new PhpWord(); - $section = $phpWord->addSection(); - - $section->addFormField('textinput')->setName('MyTextBox'); - $section->addFormField('checkbox')->setDefault(true)->setValue('Your name'); - $section->addFormField('checkbox')->setDefault(true); - $section->addFormField('dropdown')->setEntries(array('Choice 1', 'Choice 2', 'Choice 3')); - - $doc = TestHelperDOCX::getDocument($phpWord); - - $path = '/w:document/w:body/w:p[%d]/w:r/w:fldChar/w:ffData'; - $this->assertTrue($doc->elementExists(sprintf($path, 1) . '/w:textInput')); - $this->assertTrue($doc->elementExists(sprintf($path, 2) . '/w:checkBox')); - $this->assertTrue($doc->elementExists(sprintf($path, 3) . '/w:checkBox')); - $this->assertTrue($doc->elementExists(sprintf($path, 4) . '/w:ddList')); - } + // testFormFieldElements moved to Writer/Word2007/Element/FormFieldTest /** * Test SDT elements diff --git a/tests/PhpWord/Writer/Word2007/Part/SettingsTest.php b/tests/PhpWord/Writer/Word2007/Part/SettingsTest.php index 8a21e827cd..d3c1c1dd35 100644 --- a/tests/PhpWord/Writer/Word2007/Part/SettingsTest.php +++ b/tests/PhpWord/Writer/Word2007/Part/SettingsTest.php @@ -17,10 +17,10 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Part; -use PhpOffice\Common\Microsoft\PasswordEncoder; use PhpOffice\PhpWord\ComplexType\ProofState; use PhpOffice\PhpWord\ComplexType\TrackChangesView; use PhpOffice\PhpWord\PhpWord; +use PhpOffice\PhpWord\Shared\Microsoft\PasswordEncoder; use PhpOffice\PhpWord\SimpleType\Zoom; use PhpOffice\PhpWord\Style\Language; use PhpOffice\PhpWord\TestHelperDOCX; @@ -67,6 +67,8 @@ public function testDocumentProtectionWithPassword() $phpWord->getSettings()->getDocumentProtection()->setSalt(base64_decode('uq81pJRRGFIY5U+E9gt8tA==')); $phpWord->getSettings()->getDocumentProtection()->setAlgorithm(PasswordEncoder::ALGORITHM_MD2); $phpWord->getSettings()->getDocumentProtection()->setSpinCount(10); + $sect = $phpWord->addSection(); + $sect->addText('This is a protected document'); $doc = TestHelperDOCX::getDocument($phpWord); @@ -79,6 +81,31 @@ public function testDocumentProtectionWithPassword() $this->assertEquals('10', $doc->getElement($path, $file)->getAttribute('w:cryptSpinCount')); } + /** + * Test document protection with password without setting salt + */ + public function testDocumentProtectionWithPasswordNoSalt() + { + $phpWord = new PhpWord(); + $phpWord->getSettings()->getDocumentProtection()->setEditing('readOnly'); + $phpWord->getSettings()->getDocumentProtection()->setPassword('testÄö@€!$&'); + //$phpWord->getSettings()->getDocumentProtection()->setSalt(base64_decode('uq81pJRRGFIY5U+E9gt8tA==')); + $phpWord->getSettings()->getDocumentProtection()->setAlgorithm(PasswordEncoder::ALGORITHM_MD2); + $phpWord->getSettings()->getDocumentProtection()->setSpinCount(10); + $sect = $phpWord->addSection(); + $sect->addText('This is a protected document'); + + $doc = TestHelperDOCX::getDocument($phpWord); + + $file = 'word/settings.xml'; + + $path = '/w:settings/w:documentProtection'; + $this->assertTrue($doc->elementExists($path, $file)); + //$this->assertEquals('rUuJbk6LuN2/qFyp7IUPQA==', $doc->getElement($path, $file)->getAttribute('w:hash')); + $this->assertEquals('1', $doc->getElement($path, $file)->getAttribute('w:cryptAlgorithmSid')); + $this->assertEquals('10', $doc->getElement($path, $file)->getAttribute('w:cryptSpinCount')); + } + /** * Test compatibility */ diff --git a/tests/PhpWord/Writer/Word2007/Style/ImageTest.php b/tests/PhpWord/Writer/Word2007/Style/ImageTest.php index efa0a10534..c2cbfcae05 100644 --- a/tests/PhpWord/Writer/Word2007/Style/ImageTest.php +++ b/tests/PhpWord/Writer/Word2007/Style/ImageTest.php @@ -54,6 +54,42 @@ public function testWrapping() $section->addImage(__DIR__ . '/../../../_files/images/earth.jpg', $styles); $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007'); + $path = '/w:document/w:body/w:p[1]/w:r/w:rPr/w:position'; + $this->assertFalse($doc->elementExists($path)); + $path = '/w:document/w:body/w:p[1]/w:r/w:pict/v:shape'; + $this->assertTrue($doc->elementExists($path . '/w10:wrap')); + $this->assertEquals('inline', $doc->getElementAttribute($path . '/w10:wrap', 'type')); + + $this->assertTrue($doc->elementExists($path)); + $style = $doc->getElement($path)->getAttribute('style'); + $this->assertNotNull($style); + $this->assertContains('mso-wrap-distance-left:10pt;', $style); + $this->assertContains('mso-wrap-distance-right:20pt;', $style); + $this->assertContains('mso-wrap-distance-top:30pt;', $style); + $this->assertContains('mso-wrap-distance-bottom:40pt;', $style); + } + + /** + * Test writing image wrapping + */ + public function testWrappingWithPosition() + { + $styles = array( + 'wrap' => Image::WRAP_INLINE, + 'wrapDistanceLeft' => 10, + 'wrapDistanceRight' => 20, + 'wrapDistanceTop' => 30, + 'wrapDistanceBottom' => 40, + 'position' => 10, + ); + + $phpWord = new \PhpOffice\PhpWord\PhpWord(); + $section = $phpWord->addSection(); + $section->addImage(__DIR__ . '/../../../_files/images/earth.jpg', $styles); + $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007'); + + $path = '/w:document/w:body/w:p[1]/w:r/w:rPr/w:position'; + $this->assertEquals('10', $doc->getElement($path)->getAttribute('w:val')); $path = '/w:document/w:body/w:p[1]/w:r/w:pict/v:shape'; $this->assertTrue($doc->elementExists($path . '/w10:wrap')); $this->assertEquals('inline', $doc->getElementAttribute($path . '/w10:wrap', 'type')); diff --git a/tests/PhpWord/Writer/Word2007/Style/SectionTest.php b/tests/PhpWord/Writer/Word2007/Style/SectionTest.php new file mode 100644 index 0000000000..74e1eadd6b --- /dev/null +++ b/tests/PhpWord/Writer/Word2007/Style/SectionTest.php @@ -0,0 +1,57 @@ +addSection(); + $section->getStyle()->setMarginTop(0.1)->setMarginBottom(0.4)->setMarginLeft(0.2)->setMarginRight(0.3); + $section->addText('test'); + $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007'); + Settings::setMeasurementUnit($unit); + + $path = '/w:document/w:body/w:sectPr/w:pgMar'; + $this->assertEquals('144', $doc->getElementAttribute($path, 'w:top')); + $this->assertEquals('432', $doc->getElementAttribute($path, 'w:right')); + $this->assertEquals('576', $doc->getElementAttribute($path, 'w:bottom')); + $this->assertEquals('288', $doc->getElementAttribute($path, 'w:left')); + } +} diff --git a/tests/PhpWord/Writer/Word2007/StyleTest.php b/tests/PhpWord/Writer/Word2007/StyleTest.php index 48cff8713a..8bd279803d 100644 --- a/tests/PhpWord/Writer/Word2007/StyleTest.php +++ b/tests/PhpWord/Writer/Word2007/StyleTest.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWord\Writer\Word2007; -use PhpOffice\Common\XMLWriter; +use PhpOffice\PhpWord\Shared\XMLWriter; /** * Test class for PhpOffice\PhpWord\Writer\Word2007\Style subnamespace diff --git a/tests/PhpWord/_files/xml/reader.zip b/tests/PhpWord/_files/xml/reader.zip new file mode 100644 index 0000000000..dbe69cbbc0 Binary files /dev/null and b/tests/PhpWord/_files/xml/reader.zip differ diff --git a/tests/PhpWord/_includes/AbstractTestReader.php b/tests/PhpWord/_includes/AbstractTestReader.php index d9097d717f..12bd437a3d 100644 --- a/tests/PhpWord/_includes/AbstractTestReader.php +++ b/tests/PhpWord/_includes/AbstractTestReader.php @@ -24,7 +24,7 @@ abstract class AbstractTestReader extends \PHPUnit\Framework\TestCase { private $parts = array( 'styles' => array('class' => 'PhpOffice\PhpWord\Reader\Word2007\Styles', 'xml' => '{toReplace}'), - 'document' => array('class' => 'PhpOffice\PhpWord\Reader\Word2007\Document', 'xml' => '{toReplace}'), + 'document' => array('class' => 'PhpOffice\PhpWord\Reader\Word2007\Document', 'xml' => '{toReplace}'), 'footnotes' => array('class' => 'PhpOffice\PhpWord\Reader\Word2007\Footnotes', 'xml' => '{toReplace}'), 'endnotes' => array('class' => 'PhpOffice\PhpWord\Reader\Word2007\Endnotes', 'xml' => '{toReplace}'), 'settings' => array('class' => 'PhpOffice\PhpWord\Reader\Word2007\Settings', 'xml' => '{toReplace}'), diff --git a/tests/PhpWord/_includes/TestHelperDOCX.php b/tests/PhpWord/_includes/TestHelperDOCX.php index 02fa7d78a8..d35f0e3fa1 100644 --- a/tests/PhpWord/_includes/TestHelperDOCX.php +++ b/tests/PhpWord/_includes/TestHelperDOCX.php @@ -63,7 +63,12 @@ public static function getDocument(PhpWord $phpWord, $writerName = 'Word2007') $zip->close(); } - return new XmlDocument(Settings::getTempDir() . '/PhpWord_Unit_Test/'); + $doc = new XmlDocument(Settings::getTempDir() . '/PhpWord_Unit_Test/'); + if ($writerName === 'ODText') { + $doc->setDefaultFile('content.xml'); + } + + return $doc; } /** diff --git a/tests/PhpWord/_includes/XmlDocument.php b/tests/PhpWord/_includes/XmlDocument.php index 3a7869bcea..1cbc8f9576 100644 --- a/tests/PhpWord/_includes/XmlDocument.php +++ b/tests/PhpWord/_includes/XmlDocument.php @@ -50,6 +50,37 @@ class XmlDocument */ private $file; + /** + * Default file name + * + * @var string + */ + private $defaultFile = 'word/document.xml'; + + /** + * Get default file + * + * @return string + */ + public function getDefaultFile() + { + return $this->defaultFile; + } + + /** + * Set default file + * + * @param string $file + * @return string + */ + public function setDefaultFile($file) + { + $temp = $this->defaultFile; + $this->defaultFile = $file; + + return $temp; + } + /** * Create new instance * @@ -66,8 +97,11 @@ public function __construct($path) * @param string $file * @return \DOMDocument */ - public function getFileDom($file = 'word/document.xml') + public function getFileDom($file = '') { + if (!$file) { + $file = $this->defaultFile; + } if (null !== $this->dom && $file === $this->file) { return $this->dom; } @@ -76,10 +110,14 @@ public function getFileDom($file = 'word/document.xml') $this->file = $file; $file = $this->path . '/' . $file; - $orignalLibEntityLoader = libxml_disable_entity_loader(false); + if (\PHP_VERSION_ID < 80000) { + $orignalLibEntityLoader = libxml_disable_entity_loader(false); + } $this->dom = new \DOMDocument(); $this->dom->load($file); - libxml_disable_entity_loader($orignalLibEntityLoader); + if (\PHP_VERSION_ID < 80000) { + libxml_disable_entity_loader($orignalLibEntityLoader); + } return $this->dom; } @@ -91,8 +129,11 @@ public function getFileDom($file = 'word/document.xml') * @param string $file * @return \DOMNodeList */ - public function getNodeList($path, $file = 'word/document.xml') + public function getNodeList($path, $file = '') { + if (!$file) { + $file = $this->defaultFile; + } if (null === $this->dom || $file !== $this->file) { $this->getFileDom($file); } @@ -112,8 +153,11 @@ public function getNodeList($path, $file = 'word/document.xml') * @param string $file * @return \DOMElement */ - public function getElement($path, $file = 'word/document.xml') + public function getElement($path, $file = '') { + if (!$file) { + $file = $this->defaultFile; + } $elements = $this->getNodeList($path, $file); return $elements->item(0); @@ -147,8 +191,12 @@ public function getPath() * @param string $file * @return string */ - public function getElementAttribute($path, $attribute, $file = 'word/document.xml') + public function getElementAttribute($path, $attribute, $file = '') { + if (!$file) { + $file = $this->defaultFile; + } + return $this->getElement($path, $file)->getAttribute($attribute); } @@ -159,8 +207,11 @@ public function getElementAttribute($path, $attribute, $file = 'word/document.xm * @param string $file * @return string */ - public function elementExists($path, $file = 'word/document.xml') + public function elementExists($path, $file = '') { + if (!$file) { + $file = $this->defaultFile; + } $nodeList = $this->getNodeList($path, $file); return $nodeList->length != 0; @@ -173,8 +224,11 @@ public function elementExists($path, $file = 'word/document.xml') * @param string $file * @return string */ - public function printXml($path = '/', $file = 'word/document.xml') + public function printXml($path = '/', $file = '') { + if (!$file) { + $file = $this->defaultFile; + } $element = $this->getElement($path, $file); if ($element instanceof \DOMDocument) { $element->formatOutput = true;