diff --git a/.gitignore b/.gitignore index 01606063..810a7b0a 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,7 @@ Thumbs.db Desktop.ini composer.phar phpunit.xml +phpword.ini /.buildpath /.idea /.project diff --git a/.scrutinizer.yml b/.scrutinizer.yml index d253de30..6f982d8e 100644 --- a/.scrutinizer.yml +++ b/.scrutinizer.yml @@ -9,7 +9,6 @@ tools: enabled: true config: standard: PSR2 - php_cpd: true php_mess_detector: enabled: true config: @@ -17,8 +16,9 @@ tools: external_code_coverage: enabled: true timeout: 900 - php_sim: - min_mass: 30 + php_cpd: true + # php_sim: # Temporarily disabled to allow focus on things other than duplicates + # min_mass: 40 php_pdepend: true php_analyzer: true sensiolabs_security_checker: true diff --git a/.travis.yml b/.travis.yml index 190c0a3c..63165dbd 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,8 +10,6 @@ php: matrix: allow_failures: - - php: 5.3.3 - - php: 5.6 - php: hhvm env: @@ -23,14 +21,8 @@ before_script: - sudo apt-get -qq update > /dev/null - sudo apt-get -qq install graphviz > /dev/null ## Composer - # - curl -s http://getcomposer.org/installer | php - # - php composer.phar install --prefer-source - composer self-update - - composer require dompdf/dompdf:0.6.* - composer install --prefer-source --dev - ## PHP_CodeSniffer - - pyrus install pear/PHP_CodeSniffer - - phpenv rehash ## PHP Copy/Paste Detector - curl -o phpcpd.phar https://phar.phpunit.de/phpcpd.phar ## PHP Mess Detector @@ -48,7 +40,7 @@ before_script: script: ## PHP_CodeSniffer - - phpcs src/ tests/ --standard=PSR2 -n --ignore=src/PhpWord/Shared/PCLZip + - ./vendor/bin/phpcs src/ tests/ --standard=PSR2 -n --ignore=src/PhpWord/Shared/PCLZip ## PHP Copy/Paste Detector - php phpcpd.phar src/ tests/ --verbose ## PHP Mess Detector @@ -58,7 +50,7 @@ script: ## PHPUnit - phpunit -c ./ --coverage-text --coverage-html ./build/coverage ## PHPDocumentor - - vendor/bin/phpdoc.php -d ./src -t ./build/docs --ignore "*/src/PhpWord/Shared/PCLZip/*" --template="responsive-twig" + - vendor/bin/phpdoc.php -d ./src -t ./build/docs --ignore "*/src/PhpWord/Shared/*/*" --template="responsive-twig" after_script: ## PHPDocumentor diff --git a/CHANGELOG.md b/CHANGELOG.md index 4f4cd810..fce2bdac 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ This is the changelog between releases of PHPWord. Releases are listed in revers ## 0.11.0 - Not yet released -This release changed PHPWord license from LGPL 2.1 to LGPL 3. +This release marked the change of PHPWord license from LGPL 2.1 to LGPL 3; new relative and absolute positioning for image; new `TextBox` and `ListItemRun` element; refactorings of writer classes into parts, elements, and styles; and ability to add elements to PHPWord object via HTML. ### Features @@ -15,17 +15,30 @@ This release changed PHPWord license from LGPL 2.1 to LGPL 3. - HTML: Ability to add elements to PHPWord object via html - @basjan GH-231 - ListItemRun: New element that can add a list item with inline formatting like a textrun - @basjan GH-235 - Table: Ability to add table inside a cell (nested table) - @ivanlanin GH-149 +- RTF Writer: UTF8 support for RTF: Internal UTF8 text is converted to Unicode before writing - @ivanlanin GH-158 +- Table: Ability to define table width (in percent and twip) and position - @ivanlanin GH-237 +- RTF Writer: Ability to add links and page breaks in RTF - @ivanlanin GH-196 +- ListItemRun: Remove fontStyle parameter because ListItemRun is inherited from TextRun and TextRun doesn't have fontStyle - @ivanlanin +- Config: Ability to use a config file to store various common settings - @ivanlanin GH-200 +- ODT Writer: Enable inline font style in TextRun - @ivanlanin +- ODT Writer: Enable underline, strike/doublestrike, smallcaps/allcaps, superscript/subscript font style - @ivanlanin +- ODT Writer: Enable section and column - @ivanlanin +- PDF Writer: Add TCPDF and mPDF as optional PDF renderer library - @ivanlanin +- ODT Writer: Enable title element and custom document properties - @ivanlanin +- ODT Reader: Ability to read standard and custom document properties - @ivanlanin ### Bugfixes - Header: All images added to the second header were assigned to the first header - @basjan GH-222 - Conversion: Fix conversion from cm to pixel, pixel to cm, and pixel to point - @basjan GH-233 GH-234 +- PageBreak: Page break adds new line in the beginning of the new page - @ivanlanin GH-150 ### Deprecated - Static classes `Footnotes`, `Endnotes`, and `TOC` - `Writer\Word2007\Part`: `Numbering::writeNumbering()`, `Settings::writeSettings()`, `WebSettings::writeWebSettings()`, `ContentTypes::writeContentTypes()`, `Styles::writeStyles()`, `Document::writeDocument()` all changed into `write()` - `Writer\Word2007\Part\DocProps`: Split into `Writer\Word2007\Part\DocPropsCore` and `Writer\Word2007\Part\DocPropsApp` +- `Element\Title::getBookmarkId()` replaced by `Element\Title::getRelationId()` ### Miscellaneous @@ -38,6 +51,8 @@ This release changed PHPWord license from LGPL 2.1 to LGPL 3. - QA: Add `.scrutinizer.yml` and include `composer.lock` for preparation to Scrutinizer - @ivanlanin GH-186 - Writer: Refactor writer parts using composite pattern - @ivanlanin - Docs: Show code quality and test code coverage badge on README +- Style: Change behaviour of `set...` function of boolean properties; when none is defined, assumed true - @ivanlanin +- Shared: Unify PHP ZipArchive and PCLZip features into PhpWord ZipArchive - @ivanlanin ## 0.10.0 - 4 May 2014 diff --git a/composer.json b/composer.json index a7b16860..483d2701 100644 --- a/composer.json +++ b/composer.json @@ -33,14 +33,18 @@ ], "require": { "php": ">=5.3.3", - "ext-xml": "*", - "ext-zip": "*" + "ext-xml": "*" }, "require-dev": { "phpunit/phpunit": "3.7.*", - "phpdocumentor/phpdocumentor":"2.*" + "phpdocumentor/phpdocumentor":"2.*", + "squizlabs/php_codesniffer": "1.*", + "dompdf/dompdf":"0.6.*", + "tecnick.com/tcpdf": "6.*", + "mpdf/mpdf": "5.*" }, "suggest": { + "ext-zip": "Used to create docx files", "ext-gd2": "Required to add images", "ext-xmlwriter": "Required to write DOCX and ODT", "ext-xsl": "Required to apply XSL style sheet to template part", diff --git a/composer.lock b/composer.lock index 6d63264a..172e564e 100644 --- a/composer.lock +++ b/composer.lock @@ -3,7 +3,7 @@ "This file locks the dependencies of your project to a known state", "Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file" ], - "hash": "6daefa91649add98af3850b0a3f13415", + "hash": "91993ff980d11a416fcf3a7309a4044f", "packages": [ ], @@ -619,6 +619,49 @@ ], "time": "2014-04-24 13:29:03" }, + { + "name": "mpdf/mpdf", + "version": "v5.7.2", + "source": { + "type": "git", + "url": "https://github.com/finwe/mpdf.git", + "reference": "1627f9e7d2ef0f635a886f611079216ed2929717" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/finwe/mpdf/zipball/1627f9e7d2ef0f635a886f611079216ed2929717", + "reference": "1627f9e7d2ef0f635a886f611079216ed2929717", + "shasum": "" + }, + "require": { + "ext-mbstring": "*", + "php": ">=4.3.10" + }, + "type": "library", + "autoload": { + "classmap": [ + "mpdf.php", + "classes" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "GPL-1.0+" + ], + "authors": [ + { + "name": "Ian Back" + } + ], + "description": "A PHP class to generate PDF files from HTML with Unicode/UTF-8 and CJK support", + "homepage": "http://www.mpdf1.com/mpdf/index.php", + "keywords": [ + "pdf", + "php", + "utf-8" + ], + "time": "2014-05-16 07:18:10" + }, { "name": "nikic/php-parser", "version": "v0.9.4", @@ -833,16 +876,16 @@ }, { "name": "phpdocumentor/phpdocumentor", - "version": "v2.4.0", + "version": "v2.5.0", "source": { "type": "git", "url": "https://github.com/phpDocumentor/phpDocumentor2.git", - "reference": "d7503ada7386aa6b2956224d50a8d0226a22a99f" + "reference": "bf9fa40f6d00412410025b2e16eb16c315eb0216" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/phpDocumentor2/zipball/d7503ada7386aa6b2956224d50a8d0226a22a99f", - "reference": "d7503ada7386aa6b2956224d50a8d0226a22a99f", + "url": "https://api.github.com/repos/phpDocumentor/phpDocumentor2/zipball/bf9fa40f6d00412410025b2e16eb16c315eb0216", + "reference": "bf9fa40f6d00412410025b2e16eb16c315eb0216", "shasum": "" }, "require": { @@ -895,12 +938,13 @@ "ext-xslcache": "Enabling the XSLCache extension improves the generation of xml based templates." }, "bin": [ - "bin/phpdoc.php" + "bin/phpdoc.php", + "bin/phpdoc" ], "type": "library", "extra": { "branch-alias": { - "dev-develop": "2.4-dev" + "dev-develop": "2.5-dev" } }, "autoload": { @@ -924,7 +968,7 @@ "documentation", "phpdoc" ], - "time": "2014-04-01 18:14:51" + "time": "2014-05-17 12:25:35" }, { "name": "phpdocumentor/reflection", @@ -1863,6 +1907,81 @@ ], "time": "2012-12-21 11:40:51" }, + { + "name": "squizlabs/php_codesniffer", + "version": "1.5.3", + "source": { + "type": "git", + "url": "https://github.com/squizlabs/PHP_CodeSniffer.git", + "reference": "396178ada8499ec492363587f037125bf7b07fcc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/396178ada8499ec492363587f037125bf7b07fcc", + "reference": "396178ada8499ec492363587f037125bf7b07fcc", + "shasum": "" + }, + "require": { + "ext-tokenizer": "*", + "php": ">=5.1.2" + }, + "suggest": { + "phpunit/php-timer": "dev-master" + }, + "bin": [ + "scripts/phpcs" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-phpcs-fixer": "2.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "CodeSniffer.php", + "CodeSniffer/CLI.php", + "CodeSniffer/Exception.php", + "CodeSniffer/File.php", + "CodeSniffer/Report.php", + "CodeSniffer/Reporting.php", + "CodeSniffer/Sniff.php", + "CodeSniffer/Tokens.php", + "CodeSniffer/Reports/", + "CodeSniffer/CommentParser/", + "CodeSniffer/Tokenizers/", + "CodeSniffer/DocGenerators/", + "CodeSniffer/Standards/AbstractPatternSniff.php", + "CodeSniffer/Standards/AbstractScopeSniff.php", + "CodeSniffer/Standards/AbstractVariableSniff.php", + "CodeSniffer/Standards/IncorrectPatternException.php", + "CodeSniffer/Standards/Generic/Sniffs/", + "CodeSniffer/Standards/MySource/Sniffs/", + "CodeSniffer/Standards/PEAR/Sniffs/", + "CodeSniffer/Standards/PSR1/Sniffs/", + "CodeSniffer/Standards/PSR2/Sniffs/", + "CodeSniffer/Standards/Squiz/Sniffs/", + "CodeSniffer/Standards/Zend/Sniffs/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Greg Sherwood", + "role": "lead" + } + ], + "description": "PHP_CodeSniffer tokenises PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.", + "homepage": "http://www.squizlabs.com/php-codesniffer", + "keywords": [ + "phpcs", + "standards" + ], + "time": "2014-05-01 03:07:07" + }, { "name": "symfony/config", "version": "v2.4.4", @@ -2453,6 +2572,63 @@ "homepage": "http://symfony.com", "time": "2014-04-18 20:37:09" }, + { + "name": "tecnick.com/tcpdf", + "version": "6.0.078", + "source": { + "type": "git", + "url": "git://git.code.sf.net/p/tcpdf/code", + "reference": "e1cbda79b99f3cdc8fdf26b39eb4870d2cd9fbac" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "autoload": { + "classmap": [ + "fonts", + "config", + "include", + "tcpdf.php", + "tcpdf_parser.php", + "tcpdf_import.php", + "tcpdf_barcodes_1d.php", + "tcpdf_barcodes_2d.php", + "include/tcpdf_colors.php", + "include/tcpdf_filters.php", + "include/tcpdf_font_data.php", + "include/tcpdf_fonts.php", + "include/tcpdf_images.php", + "include/tcpdf_static.php", + "include/barcodes/datamatrix.php", + "include/barcodes/pdf417.php", + "include/barcodes/qrcode.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "LGPLv3" + ], + "authors": [ + { + "name": "Nicola Asuni", + "email": "info@tecnick.com", + "homepage": "http://nicolaasuni.tecnick.com" + } + ], + "description": "TCPDF is a PHP class for generating PDF documents.", + "homepage": "http://www.tcpdf.org/", + "keywords": [ + "PDFD32000-2008", + "TCPDF", + "barcodes", + "datamatrix", + "pdf", + "pdf417", + "qrcode" + ], + "time": "2014-05-12 19:50:13" + }, { "name": "twig/twig", "version": "v1.15.1", diff --git a/docs/intro.rst b/docs/intro.rst index 25a50205..3c6277f5 100644 --- a/docs/intro.rst +++ b/docs/intro.rst @@ -61,25 +61,23 @@ Writers +---------------------------+----------------------+--------+-------+-------+--------+-------+ | Features | | DOCX | ODT | RTF | HTML | PDF | +===========================+======================+========+=======+=======+========+=======+ -| **Document Properties** | Standard | ✓ | | | | | +| **Document Properties** | Standard | ✓ | ✓ | | | | +---------------------------+----------------------+--------+-------+-------+--------+-------+ -| | Extended | ✓ | | | | | -+---------------------------+----------------------+--------+-------+-------+--------+-------+ -| | UserDefined | ✓ | | | | | +| | Custom | ✓ | ✓ | | | | +---------------------------+----------------------+--------+-------+-------+--------+-------+ | **Element Type** | Text | ✓ | ✓ | ✓ | ✓ | ✓ | +---------------------------+----------------------+--------+-------+-------+--------+-------+ | | Text Run | ✓ | ✓ | ✓ | ✓ | ✓ | +---------------------------+----------------------+--------+-------+-------+--------+-------+ -| | Title | ✓ | | | ✓ | ✓ | +| | Title | ✓ | ✓ | | ✓ | ✓ | +---------------------------+----------------------+--------+-------+-------+--------+-------+ -| | Link | ✓ | ✓ | | ✓ | ✓ | +| | Link | ✓ | ✓ | ✓ | ✓ | ✓ | +---------------------------+----------------------+--------+-------+-------+--------+-------+ | | Preserve Text | ✓ | | | | | +---------------------------+----------------------+--------+-------+-------+--------+-------+ | | Text Break | ✓ | ✓ | ✓ | ✓ | ✓ | +---------------------------+----------------------+--------+-------+-------+--------+-------+ -| | Page Break | ✓ | | | | | +| | Page Break | ✓ | | ✓ | | | +---------------------------+----------------------+--------+-------+-------+--------+-------+ | | List | ✓ | | | | | +---------------------------+----------------------+--------+-------+-------+--------+-------+ @@ -124,9 +122,7 @@ Readers +===========================+======================+========+=======+=======+ | **Document Properties** | Standard | ✓ | | | +---------------------------+----------------------+--------+-------+-------+ -| | Extended | ✓ | | | -+---------------------------+----------------------+--------+-------+-------+ -| | UserDefined | ✓ | | | +| | Custom | ✓ | | | +---------------------------+----------------------+--------+-------+-------+ | **Element Type** | Text | ✓ | ✓ | | +---------------------------+----------------------+--------+-------+-------+ diff --git a/docs/src/documentation.md b/docs/src/documentation.md index a140c5ba..ffa3edc3 100644 --- a/docs/src/documentation.md +++ b/docs/src/documentation.md @@ -78,16 +78,15 @@ Below are the supported features for each file formats. | Features | | DOCX | ODT | RTF | HTML | PDF | |-------------------------|--------------------|------|-----|-----|------|-----| -| **Document Properties** | Standard | ✓ | | | | | -| | Extended | ✓ | | | | | -| | UserDefined | ✓ | | | | | +| **Document Properties** | Standard | ✓ | ✓ | | | | +| | Custom | ✓ | ✓ | | | | | **Element Type** | Text | ✓ | ✓ | ✓ | ✓ | ✓ | | | Text Run | ✓ | ✓ | ✓ | ✓ | ✓ | -| | Title | ✓ | | | ✓ | ✓ | -| | Link | ✓ | ✓ | | ✓ | ✓ | +| | Title | ✓ | ✓ | | ✓ | ✓ | +| | Link | ✓ | ✓ | ✓ | ✓ | ✓ | | | Preserve Text | ✓ | | | | | | | Text Break | ✓ | ✓ | ✓ | ✓ | ✓ | -| | Page Break | ✓ | | | | | +| | Page Break | ✓ | | ✓ | | | | | List | ✓ | | | | | | | Table | ✓ | ✓ | | ✓ | ✓ | | | Image | ✓ | ✓ | | ✓ | | @@ -111,8 +110,7 @@ Below are the supported features for each file formats. | Features | | DOCX | ODT | RTF | |-------------------------|--------------------|------|-----|-----| | **Document Properties** | Standard | ✓ | | | -| | Extended | ✓ | | | -| | UserDefined | ✓ | | | +| | Custom | ✓ | | | | **Element Type** | Text | ✓ | ✓ | | | | Text Run | ✓ | | | | | Title | ✓ | ✓ | | diff --git a/phpmd.xml.dist b/phpmd.xml.dist index 18d5b2a9..f0b62b2d 100644 --- a/phpmd.xml.dist +++ b/phpmd.xml.dist @@ -8,11 +8,17 @@ - + - + + + + + + + diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 09524450..015dd2ed 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -10,7 +10,7 @@ syntaxCheck="false"> - ./tests/PhpWord/ + ./tests/PhpWord @@ -22,9 +22,6 @@ - diff --git a/phpword.ini.dist b/phpword.ini.dist new file mode 100644 index 00000000..4a51ee11 --- /dev/null +++ b/phpword.ini.dist @@ -0,0 +1,14 @@ +; Default config file for PHPWord +; Copy this file into phpword.ini and use Settings::loadConfig to load + +[General] + +compatibility = true +zipClass = ZipArchive +pdfRendererName = DomPDF +pdfRendererPath = + +[Font] + +defaultFontName = Arial +defaultFontSize = 10 diff --git a/samples/Sample_01_SimpleText.php b/samples/Sample_01_SimpleText.php index 7202ed7e..311f3350 100644 --- a/samples/Sample_01_SimpleText.php +++ b/samples/Sample_01_SimpleText.php @@ -22,7 +22,8 @@ $section->addTextBreak(2); $section->addText('I am styled by a font style definition.', 'rStyle'); $section->addText('I am styled by a paragraph style definition.', null, 'pStyle'); $section->addText('I am styled by both font and paragraph style.', 'rStyle', 'pStyle'); -$section->addTextBreak(); + +$section->addPageBreak(); // Inline font style $fontStyle['name'] = 'Times New Roman'; @@ -36,10 +37,11 @@ $fontStyle['color'] = 'FF0000'; $fontStyle['fgColor'] = 'yellow'; $fontStyle['smallCaps'] = true; $section->addText('I am inline styled.', $fontStyle); + $section->addTextBreak(); // Link -$section->addLink('http://www.google.com', null, 'NLink'); +$section->addLink('http://www.google.com', 'Google'); $section->addTextBreak(); // Image diff --git a/samples/Sample_05_Multicolumn.php b/samples/Sample_05_Multicolumn.php index a3083824..f4737060 100644 --- a/samples/Sample_05_Multicolumn.php +++ b/samples/Sample_05_Multicolumn.php @@ -18,7 +18,7 @@ $section = $phpWord->addSection(array( 'colsNum' => 2, 'colsSpace' => 1440, 'breakType' => 'continuous')); -$section->addText('Three columns, one inch (1440 twips) spacing. ' . $filler); +$section->addText('Two columns, one inch (1440 twips) spacing. ' . $filler); // Normal $section = $phpWord->addSection(array('breakType' => 'continuous')); diff --git a/samples/Sample_09_Tables.php b/samples/Sample_09_Tables.php index 5f77f8db..882653bc 100644 --- a/samples/Sample_09_Tables.php +++ b/samples/Sample_09_Tables.php @@ -51,7 +51,7 @@ for($i = 1; $i <= 8; $i++) { // 3. colspan (gridSpan) and rowspan (vMerge) -$section->addTextBreak(1); +$section->addPageBreak(); $section->addText("Table with colspan and rowspan", $header); $styleTable = array('borderSize' => 6, 'borderColor' => '999999'); @@ -87,11 +87,12 @@ $table->addCell(null, $cellRowContinue); // 4. Nested table $section->addTextBreak(2); -$section->addText('Nested table', $header); +$section->addText('Nested table in a centered and 50% width table.', $header); -$cell = $section->addTable()->addRow()->addCell(); +$table = $section->addTable(array('width' => 50 * 50, 'unit' => 'pct', 'align' => 'center')); +$cell = $table->addRow()->addCell(); $cell->addText('This cell contains nested table.'); -$innerCell = $cell->addTable()->addRow()->addCell(); +$innerCell = $cell->addTable(array('align' => 'center'))->addRow()->addCell(); $innerCell->addText('Inside nested table'); // Save file diff --git a/samples/Sample_25_TextBox.php b/samples/Sample_25_TextBox.php index 4beb9553..0a659ddb 100644 --- a/samples/Sample_25_TextBox.php +++ b/samples/Sample_25_TextBox.php @@ -8,7 +8,7 @@ $phpWord = new \PhpOffice\PhpWord\PhpWord(); $section = $phpWord->addSection(); // In section -$textbox = $section->addTextBox(array('align' => 'left', 'width' => 400, 'height' => 150, 'borderSize' => 1, 'borderColor' => '#FF0000')); +$textbox = $section->addTextBox(array('align' => 'center', 'width' => 400, 'height' => 150, 'borderSize' => 1, 'borderColor' => '#FF0000')); $textbox->addText('Text box content in section.'); $textbox->addText('Another line.'); $cell = $textbox->addTable()->addRow()->addCell(); @@ -22,7 +22,7 @@ $textbox->addText('Textbox inside table'); // Inside header with textrun $header = $section->addHeader(); -$textbox = $header->addTextBox(array('align' => 'center', 'width' => 600, 'borderSize' => 1, 'borderColor' => '#00FF00')); +$textbox = $header->addTextBox(array('width' => 600, 'borderSize' => 1, 'borderColor' => '#00FF00')); $textrun = $textbox->addTextRun(); $textrun->addText('TextBox in header. TextBox can contain a TextRun '); $textrun->addText('with bold text', array('bold' => true)); diff --git a/samples/Sample_Header.php b/samples/Sample_Header.php index e7a24b19..b752848d 100644 --- a/samples/Sample_Header.php +++ b/samples/Sample_Header.php @@ -2,23 +2,25 @@ /** * Header file */ -error_reporting(E_ALL); +use PhpOffice\PhpWord\Autoloader; +use PhpOffice\PhpWord\Settings; +use PhpOffice\PhpWord\IOFactory; + +error_reporting(E_ALL & ~E_DEPRECATED); define('CLI', (PHP_SAPI == 'cli') ? true : false); define('EOL', CLI ? PHP_EOL : '
'); define('SCRIPT_FILENAME', basename($_SERVER['SCRIPT_FILENAME'], '.php')); define('IS_INDEX', SCRIPT_FILENAME == 'index'); require_once '../src/PhpWord/Autoloader.php'; -\PhpOffice\PhpWord\Autoloader::register(); +Autoloader::register(); +Settings::loadConfig(); // Set writers $writers = array('Word2007' => 'docx', 'ODText' => 'odt', 'RTF' => 'rtf', 'HTML' => 'html', 'PDF' => 'pdf'); // Set PDF renderer -$rendererName = \PhpOffice\PhpWord\Settings::PDF_RENDERER_DOMPDF; -$rendererLibraryPath = ''; // DomPDF library path - -if (!\PhpOffice\PhpWord\Settings::setPdfRenderer($rendererName, $rendererLibraryPath)) { +if (Settings::getPdfRendererPath() === null) { $writers['PDF'] = null; } @@ -60,7 +62,7 @@ function write($phpWord, $filename, $writers) foreach ($writers as $writer => $extension) { $result .= date('H:i:s') . " Write to {$writer} format"; if (!is_null($extension)) { - $xmlWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, $writer); + $xmlWriter = IOFactory::createWriter($phpWord, $writer); $xmlWriter->save("{$filename}.{$extension}"); rename("{$filename}.{$extension}", "results/{$filename}.{$extension}"); } else { diff --git a/samples/index.php b/samples/index.php index 71e8518a..94b98901 100644 --- a/samples/index.php +++ b/samples/index.php @@ -10,7 +10,7 @@ if (!CLI) { Read the Docs

- array('PHP 5.3.0', version_compare(phpversion(), '5.3.0', '>=')), 'zip' => array('PHP extension ZipArchive', extension_loaded('zip')), diff --git a/samples/resources/Sample_11_ReadWord2007.docx b/samples/resources/Sample_11_ReadWord2007.docx index aefe9f48..c9a50f48 100644 Binary files a/samples/resources/Sample_11_ReadWord2007.docx and b/samples/resources/Sample_11_ReadWord2007.docx differ diff --git a/samples/resources/Sample_24_ReadODText.odt b/samples/resources/Sample_24_ReadODText.odt index 9e18e619..d37c4e66 100644 Binary files a/samples/resources/Sample_24_ReadODText.odt and b/samples/resources/Sample_24_ReadODText.odt differ diff --git a/src/PhpWord/DocumentProperties.php b/src/PhpWord/DocumentProperties.php index a2d869b0..17d57c1d 100644 --- a/src/PhpWord/DocumentProperties.php +++ b/src/PhpWord/DocumentProperties.php @@ -416,8 +416,9 @@ class DocumentProperties { if ($this->isCustomPropertySet($propertyName)) { return $this->customProperties[$propertyName]['value']; + } else { + return null; } - } /** @@ -430,8 +431,9 @@ class DocumentProperties { if ($this->isCustomPropertySet($propertyName)) { return $this->customProperties[$propertyName]['type']; + } else { + return null; } - } /** diff --git a/src/PhpWord/Element/AbstractContainer.php b/src/PhpWord/Element/AbstractContainer.php index 5cff4bbd..f141f4f0 100644 --- a/src/PhpWord/Element/AbstractContainer.php +++ b/src/PhpWord/Element/AbstractContainer.php @@ -35,15 +35,81 @@ abstract class AbstractContainer extends AbstractElement protected $elements = array(); /** - * Set element index and unique id, and add element into elements collection + * Container type Section|Header|Footer|Footnote|Endnote|Cell|TextRun|TextBox|ListItemRun + * + * @var string */ - protected function addElement(AbstractElement $element) + protected $container; + + /** + * Add element + * + * Each element has different number of parameters passed + * + * @param string $elementName + * @return \PhpOffice\PhpWord\Element\AbstractElement + */ + protected function addElement($elementName) { - // $type = str_replace('PhpOffice\\PhpWord\\Element\\', '', get_class($element))); + $elementClass = __NAMESPACE__ . '\\' . $elementName; + $this->checkValidity($elementName); + + // Get arguments + $args = func_get_args(); + $argsCount = func_num_args(); + $withoutP = in_array($this->container, array('TextRun', 'Footnote', 'Endnote', 'ListItemRun')); + if ($withoutP && ($elementName == 'Text' || $elementName == 'PreserveText')) { + $args[3] = null; + } + + // Create element dynamically + + /** @var \PhpOffice\PhpWord\Element\AbstractElement $element Type hint */ + if ($argsCount == 2) { // TextRun, TextBox, Table, Footnote, Endnote + $element = new $elementClass($args[1]); + } elseif ($argsCount == 3) { // Object, TextBreak, Title + $element = new $elementClass($args[1], $args[2]); + } elseif ($argsCount == 4) { // PreserveText, Text, Image + $element = new $elementClass($args[1], $args[2], $args[3]); + } elseif ($argsCount == 5) { // CheckBox, Link, ListItemRun, TOC + $element = new $elementClass($args[1], $args[2], $args[3], $args[4]); + } elseif ($argsCount == 6) { // ListItem + $element = new $elementClass($args[1], $args[2], $args[3], $args[4], $args[5]); + } else { // Page Break + $element = new $elementClass(); + } + + // Set relation Id for media collection + $mediaContainer = $this->getMediaContainer(); + if (in_array($elementName, array('Link', 'Image', 'Object'))) { + if ($elementName == 'Image') { + $rId = Media::addElement($mediaContainer, strtolower($elementName), $args[1], $element); + } else { + $rId = Media::addElement($mediaContainer, strtolower($elementName), $args[1]); + } + $element->setRelationId($rId); + } + if ($elementName == 'Object') { + /** @var \PhpOffice\PhpWord\Element\Object $element Type hint */ + $rIdIcon = Media::addElement($mediaContainer, 'image', $element->getIcon(), new Image($element->getIcon())); + $element->setImageRelationId($rIdIcon); + } + + // Set relation Id for other collection + if (in_array($elementName, array('Footnote', 'Endnote', 'Title')) && $this->phpWord instanceof PhpWord) { + $addMethod = "add{$elementName}"; + $rId = $this->phpWord->$addMethod($element); + $element->setRelationId($rId); + } + + // Set other properties and add element into collection + $element->setDocPart($this->getDocPart(), $this->getDocPartId()); $element->setElementIndex($this->countElements() + 1); $element->setElementId(); $element->setPhpWord($this->phpWord); $this->elements[] = $element; + + return $element; } /** @@ -59,62 +125,24 @@ abstract class AbstractContainer extends AbstractElement /** * Count elements * - * @return integer + * @return int */ public function countElements() { return count($this->elements); } - /** - * Add generic element with style - * - * This is how all elements should be added with dependency injection: with - * just one simple $style. Currently this function supports TextRun, Table, - * and TextBox since all other elements have different arguments - * - * @todo Change the function name into something better? - * - * @param string $elementName - * @param mixed $style - * @return \PhpOffice\PhpWord\Element\AbstractElement - */ - private function addGenericElement($elementName, $style) - { - $elementClass = __NAMESPACE__ . '\\' . $elementName; - - $this->checkValidity($elementName); - $element = new $elementClass($style); - $element->setDocPart($this->getDocPart(), $this->getDocPartId()); - $this->addElement($element); - - return $element; - } - /** * Add text/preservetext element * * @param string $text * @param mixed $fontStyle * @param mixed $paragraphStyle - * @param string $elementName Text|PreserveText * @return \PhpOffice\PhpWord\Element\Text|\PhpOffice\PhpWord\Element\PreserveText */ - public function addText($text, $fontStyle = null, $paragraphStyle = null, $elementName = 'Text') + public function addText($text, $fontStyle = null, $paragraphStyle = null) { - $this->checkValidity($elementName); - $elementClass = substr(get_class($this), 0, strrpos(get_class($this), '\\')) . '\\' . $elementName; - - // Reset paragraph style for footnote and textrun. They have their own - if (in_array($this->container, array('textrun', 'footnote', 'endnote', 'listitemrun'))) { - $paragraphStyle = null; - } - - $element = new $elementClass($text, $fontStyle, $paragraphStyle); - $element->setDocPart($this->getDocPart(), $this->getDocPartId()); - $this->addElement($element); - - return $element; + return $this->addElement('Text', $text, $fontStyle, $paragraphStyle); } /** @@ -125,7 +153,7 @@ abstract class AbstractContainer extends AbstractElement */ public function addTextRun($paragraphStyle = null) { - return $this->addGenericElement('TextRun', $paragraphStyle); + return $this->addElement('TextRun', $paragraphStyle); } /** @@ -153,18 +181,7 @@ abstract class AbstractContainer extends AbstractElement */ public function addLink($target, $text = null, $fontStyle = null, $paragraphStyle = null) { - $this->checkValidity('Link'); - $elementDocPart = $this->checkElementDocPart(); - - $element = new Link($target, $text, $fontStyle, $paragraphStyle); - $element->setDocPart($this->getDocPart(), $this->getDocPartId()); - - $rId = Media::addElement($elementDocPart, 'link', $target); - $element->setRelationId($rId); - - $this->addElement($element); - - return $element; + return $this->addElement('Link', $target, $text, $fontStyle, $paragraphStyle); } /** @@ -177,7 +194,7 @@ abstract class AbstractContainer extends AbstractElement */ public function addPreserveText($text, $fontStyle = null, $paragraphStyle = null) { - return $this->addText($text, $fontStyle, $paragraphStyle, 'PreserveText'); + return $this->addElement('PreserveText', $text, $fontStyle, $paragraphStyle); } /** @@ -189,12 +206,8 @@ abstract class AbstractContainer extends AbstractElement */ public function addTextBreak($count = 1, $fontStyle = null, $paragraphStyle = null) { - $this->checkValidity('TextBreak'); - for ($i = 1; $i <= $count; $i++) { - $element = new TextBreak($fontStyle, $paragraphStyle); - $element->setDocPart($this->getDocPart(), $this->getDocPartId()); - $this->addElement($element); + $this->addElement('TextBreak', $fontStyle, $paragraphStyle); } } @@ -210,33 +223,20 @@ abstract class AbstractContainer extends AbstractElement */ public function addListItem($text, $depth = 0, $fontStyle = null, $listStyle = null, $paragraphStyle = null) { - $this->checkValidity('ListItem'); - - $element = new ListItem($text, $depth, $fontStyle, $listStyle, $paragraphStyle); - $element->setDocPart($this->getDocPart(), $this->getDocPartId()); - $this->addElement($element); - - return $element; + return $this->addElement('ListItem', $text, $depth, $fontStyle, $listStyle, $paragraphStyle); } /** * Add listitemrun element * * @param int $depth - * @param mixed $fontStyle * @param mixed $listStyle * @param mixed $paragraphStyle * @return \PhpOffice\PhpWord\Element\ListItemRun */ - public function addListItemRun($depth = 0, $fontStyle = null, $listStyle = null, $paragraphStyle = null) + public function addListItemRun($depth = 0, $listStyle = null, $paragraphStyle = null) { - $this->checkValidity('ListItemRun'); - - $element = new ListItemRun($depth, $fontStyle, $listStyle, $paragraphStyle); - $element->setDocPart($this->getDocPart(), $this->getDocPartId()); - $this->addElement($element); - - return $element; + return $this->addElement('ListItemRun', $depth, $listStyle, $paragraphStyle); } /** @@ -244,11 +244,10 @@ abstract class AbstractContainer extends AbstractElement * * @param mixed $style * @return \PhpOffice\PhpWord\Element\Table - * @todo Merge with the same function on Footer */ public function addTable($style = null) { - return $this->addGenericElement('Table', $style); + return $this->addElement('Table', $style); } /** @@ -256,23 +255,12 @@ abstract class AbstractContainer extends AbstractElement * * @param string $source * @param mixed $style Image style - * @param boolean $isWatermark + * @param bool $isWatermark * @return \PhpOffice\PhpWord\Element\Image */ public function addImage($source, $style = null, $isWatermark = false) { - $this->checkValidity('Image'); - $elementDocPart = $this->checkElementDocPart(); - - $element = new Image($source, $style, $isWatermark); - $element->setDocPart($this->getDocPart(), $this->getDocPartId()); - - $rId = Media::addElement($elementDocPart, 'image', $source, $element); - $element->setRelationId($rId); - - $this->addElement($element); - - return $element; + return $this->addElement('Image', $source, $style, $isWatermark); } /** @@ -283,49 +271,21 @@ abstract class AbstractContainer extends AbstractElement * @param string $source * @param mixed $style * @return \PhpOffice\PhpWord\Element\Object - * @throws \PhpOffice\PhpWord\Exception\Exception */ public function addObject($source, $style = null) { - $this->checkValidity('Object'); - $elementDocPart = $this->checkElementDocPart(); - - $element = new Object($source, $style); - $element->setDocPart($this->getDocPart(), $this->getDocPartId()); - - $rId = Media::addElement($elementDocPart, 'object', $source); - $element->setRelationId($rId); - $rIdIcon = Media::addElement($elementDocPart, 'image', $element->getIcon(), new Image($element->getIcon())); - $element->setImageRelationId($rIdIcon); - - $this->addElement($element); - - return $element; + return $this->addElement('Object', $source, $style); } /** * Add footnote element * * @param mixed $paragraphStyle - * @param string $elementName * @return \PhpOffice\PhpWord\Element\Footnote */ - public function addFootnote($paragraphStyle = null, $elementName = 'Footnote') + public function addFootnote($paragraphStyle = null) { - $this->checkValidity($elementName); - $elementClass = substr(get_class($this), 0, strrpos(get_class($this), '\\')) . '\\' . $elementName; - $docPart = strtolower($elementName); - $addMethod = "add{$elementName}"; - - $element = new $elementClass($paragraphStyle); - $element->setDocPart($docPart, $this->getDocPartId()); - if ($this->phpWord instanceof PhpWord) { - $rId = $this->phpWord->$addMethod($element); - $element->setRelationId($rId); - } - $this->addElement($element); - - return $element; + return $this->addElement('Footnote', $paragraphStyle); } /** @@ -336,7 +296,7 @@ abstract class AbstractContainer extends AbstractElement */ public function addEndnote($paragraphStyle = null) { - return $this->addFootnote($paragraphStyle, 'Endnote'); + return $this->addElement('Endnote', $paragraphStyle); } /** @@ -350,13 +310,7 @@ abstract class AbstractContainer extends AbstractElement */ public function addCheckBox($name, $text, $fontStyle = null, $paragraphStyle = null) { - $this->checkValidity('CheckBox'); - - $element = new CheckBox($name, $text, $fontStyle, $paragraphStyle); - $element->setDocPart($this->getDocPart(), $this->getDocPartId()); - $this->addElement($element); - - return $element; + return $this->addElement('CheckBox', $name, $text, $fontStyle, $paragraphStyle); } /** @@ -367,47 +321,51 @@ abstract class AbstractContainer extends AbstractElement */ public function addTextBox($style = null) { - return $this->addGenericElement('TextBox', $style); + return $this->addElement('TextBox', $style); } /** * Check if a method is allowed for the current container * * @param string $method - * @return boolean + * @return bool + * @throws \BadMethodCallException */ private function checkValidity($method) { // Valid containers for each element - $allContainers = array('section', 'header', 'footer', 'cell', 'textrun', 'footnote', 'endnote', 'textbox', 'listitemrun'); + $allContainers = array( + 'Section', 'Header', 'Footer', 'Footnote', 'Endnote', + 'Cell', 'TextRun', 'TextBox', 'ListItemRun', + ); $validContainers = array( 'Text' => $allContainers, 'Link' => $allContainers, 'TextBreak' => $allContainers, 'Image' => $allContainers, 'Object' => $allContainers, - 'TextRun' => array('section', 'header', 'footer', 'cell', 'textbox'), - 'ListItem' => array('section', 'header', 'footer', 'cell', 'textbox'), - 'ListItemRun' => array('section', 'header', 'footer', 'cell', 'textbox'), - 'Table' => array('section', 'header', 'footer', 'cell', 'textbox'), - 'CheckBox' => array('section', 'header', 'footer', 'cell'), - 'TextBox' => array('section', 'header', 'footer', 'cell'), - 'Footnote' => array('section', 'textrun', 'cell'), - 'Endnote' => array('section', 'textrun', 'cell'), - 'PreserveText' => array('header', 'footer', 'cell'), + 'TextRun' => array('Section', 'Header', 'Footer', 'Cell', 'TextBox'), + 'ListItem' => array('Section', 'Header', 'Footer', 'Cell', 'TextBox'), + 'ListItemRun' => array('Section', 'Header', 'Footer', 'Cell', 'TextBox'), + 'Table' => array('Section', 'Header', 'Footer', 'Cell', 'TextBox'), + 'CheckBox' => array('Section', 'Header', 'Footer', 'Cell'), + 'TextBox' => array('Section', 'Header', 'Footer', 'Cell'), + 'Footnote' => array('Section', 'TextRun', 'Cell'), + 'Endnote' => array('Section', 'TextRun', 'Cell'), + 'PreserveText' => array('Header', 'Footer', 'Cell'), ); // Special condition, e.g. preservetext can only exists in cell when // the cell is located in header or footer $validSubcontainers = array( - 'PreserveText' => array(array('cell'), array('header', 'footer')), - 'Footnote' => array(array('cell', 'textrun'), array('section')), - 'Endnote' => array(array('cell', 'textrun'), array('section')), + 'PreserveText' => array(array('Cell'), array('Header', 'Footer')), + 'Footnote' => array(array('Cell', 'TextRun'), array('Section')), + 'Endnote' => array(array('Cell', 'TextRun'), array('Section')), ); // Check if a method is valid for current container if (array_key_exists($method, $validContainers)) { if (!in_array($this->container, $validContainers[$method])) { - throw new \BadMethodCallException("Cannot put $method in $this->container."); + throw new \BadMethodCallException("Cannot add $method in $this->container."); } } // Check if a method is valid for current container, located in other container @@ -417,7 +375,7 @@ abstract class AbstractContainer extends AbstractElement $allowedDocParts = $rules[1]; foreach ($containers as $container) { if ($this->container == $container && !in_array($this->getDocPart(), $allowedDocParts)) { - throw new \BadMethodCallException("Cannot put $method in $this->container."); + throw new \BadMethodCallException("Cannot add $method in $this->container."); } } } @@ -426,17 +384,21 @@ abstract class AbstractContainer extends AbstractElement } /** - * Return element location in document: section, headerx, or footerx + * Return media element (image, object, link) container name + * + * @return string section|headerx|footerx|footnote|endnote */ - private function checkElementDocPart() + private function getMediaContainer() { - $inOtherPart = in_array($this->container, array('cell', 'textrun', 'textbox', 'listitemrun')); - $docPart = $inOtherPart ? $this->getDocPart() : $this->container; - $docPartId = $inOtherPart ? $this->getDocPartId() : $this->sectionId; - $inHeaderFooter = ($docPart == 'header' || $docPart == 'footer'); - $docPartId = $inHeaderFooter ? $this->getDocPartId() : $docPartId; + $partName = $this->container; + if (in_array($partName, array('Cell', 'TextRun', 'TextBox', 'ListItemRun'))) { + $partName = $this->getDocPart(); + } + if ($partName == 'Header' || $partName == 'Footer') { + $partName .= $this->getDocPartId(); + } - return $inHeaderFooter ? $docPart . $docPartId : $docPart; + return strtolower($partName); } /** @@ -444,6 +406,7 @@ abstract class AbstractContainer extends AbstractElement * * @param string $src * @param mixed $style + * @return \PhpOffice\PhpWord\Element\Image * @deprecated 0.9.0 * @codeCoverageIgnore */ @@ -456,6 +419,7 @@ abstract class AbstractContainer extends AbstractElement * Create textrun element * * @param mixed $paragraphStyle + * @return \PhpOffice\PhpWord\Element\TextRun * @deprecated 0.10.0 * @codeCoverageIgnore */ @@ -468,6 +432,7 @@ abstract class AbstractContainer extends AbstractElement * Create footnote element * * @param mixed $paragraphStyle + * @return \PhpOffice\PhpWord\Element\Footnote * @deprecated 0.10.0 * @codeCoverageIgnore */ diff --git a/src/PhpWord/Element/AbstractElement.php b/src/PhpWord/Element/AbstractElement.php index 7e3151e2..45311364 100644 --- a/src/PhpWord/Element/AbstractElement.php +++ b/src/PhpWord/Element/AbstractElement.php @@ -34,13 +34,6 @@ abstract class AbstractElement */ protected $phpWord; - /** - * Container type section|header|footer|cell|textrun|footnote|endnote|textbox - * - * @var string - */ - protected $container; - /** * Section Id * @@ -57,7 +50,7 @@ abstract class AbstractElement * * @var string */ - protected $docPart = 'section'; + protected $docPart = 'Section'; /** * Document part Id @@ -66,21 +59,21 @@ abstract class AbstractElement * because the max number of header/footer in every page is 3, i.e. * AUTO, FIRST, and EVEN (AUTO = ODD) * - * @var integer + * @var int */ protected $docPartId = 1; /** * Index of element in the elements collection (start with 1) * - * @var integer + * @var int */ protected $elementIndex = 1; /** * Unique Id for element * - * @var integer + * @var int */ protected $elementId; @@ -114,7 +107,7 @@ abstract class AbstractElement /** * Get section number * - * @return integer + * @return int */ public function getSectionId() { @@ -125,7 +118,7 @@ abstract class AbstractElement * Set doc part * * @param string $docPart - * @param integer $docPartId + * @param int $docPartId */ public function setDocPart($docPart, $docPartId = 1) { @@ -146,7 +139,7 @@ abstract class AbstractElement /** * Get doc part Id * - * @return integer + * @return int */ public function getDocPartId() { @@ -212,13 +205,13 @@ abstract class AbstractElement } /** - * Check if element is located in section doc part (as opposed to header/footer) + * Check if element is located in Section doc part (as opposed to Header/Footer) * - * @return boolean + * @return bool */ public function isInSection() { - return ($this->docPart == 'section'); + return ($this->docPart == 'Section'); } /** @@ -226,7 +219,8 @@ abstract class AbstractElement * * @param mixed $styleObject Style object * @param mixed $styleValue Style value - * @param boolean $returnObject Always return object + * @param bool $returnObject Always return object + * @return mixed */ protected function setStyle($styleObject, $styleValue = null, $returnObject = false) { diff --git a/src/PhpWord/Element/Cell.php b/src/PhpWord/Element/Cell.php index bc9b47b4..ea49bc7b 100644 --- a/src/PhpWord/Element/Cell.php +++ b/src/PhpWord/Element/Cell.php @@ -24,6 +24,11 @@ use PhpOffice\PhpWord\Style\Cell as CellStyle; */ class Cell extends AbstractContainer { + /** + * @var string Container type + */ + protected $container = 'Cell'; + /** * Cell width * @@ -36,22 +41,18 @@ class Cell extends AbstractContainer * * @var \PhpOffice\PhpWord\Style\Cell */ - private $cellStyle; + private $style; /** * Create new instance * - * @param string $docPart section|header|footer - * @param int $docPartId * @param int $width * @param array|\PhpOffice\PhpWord\Style\Cell $style */ - public function __construct($docPart, $docPartId, $width = null, $style = null) + public function __construct($width = null, $style = null) { - $this->container = 'cell'; - $this->setDocPart($docPart, $docPartId); $this->width = $width; - $this->cellStyle = $this->setStyle(new CellStyle(), $style, true); + $this->style = $this->setStyle(new CellStyle(), $style, true); } /** @@ -61,7 +62,7 @@ class Cell extends AbstractContainer */ public function getStyle() { - return $this->cellStyle; + return $this->style; } /** diff --git a/src/PhpWord/Element/Endnote.php b/src/PhpWord/Element/Endnote.php index 03ef3b68..20278898 100644 --- a/src/PhpWord/Element/Endnote.php +++ b/src/PhpWord/Element/Endnote.php @@ -26,6 +26,11 @@ use PhpOffice\PhpWord\Style\Paragraph; */ class Endnote extends Footnote { + /** + * @var string Container type + */ + protected $container = 'Endnote'; + /** * Create new instance * @@ -33,7 +38,6 @@ class Endnote extends Footnote */ public function __construct($paragraphStyle = null) { - $this->container = 'endnote'; $this->paragraphStyle = $this->setStyle(new Paragraph(), $paragraphStyle); } } diff --git a/src/PhpWord/Element/Footer.php b/src/PhpWord/Element/Footer.php index 265c2c4c..142ccfda 100644 --- a/src/PhpWord/Element/Footer.php +++ b/src/PhpWord/Element/Footer.php @@ -33,11 +33,9 @@ class Footer extends AbstractContainer const EVEN = 'even'; /** - * Container type - * - * @var string + * @var string Container type */ - protected $container = 'footer'; + protected $container = 'Footer'; /** * Header type diff --git a/src/PhpWord/Element/Footnote.php b/src/PhpWord/Element/Footnote.php index d59a10a5..76311c6b 100644 --- a/src/PhpWord/Element/Footnote.php +++ b/src/PhpWord/Element/Footnote.php @@ -24,6 +24,11 @@ use PhpOffice\PhpWord\Style\Paragraph; */ class Footnote extends AbstractContainer { + /** + * @var string Container type + */ + protected $container = 'Footnote'; + /** * Paragraph style * @@ -38,7 +43,6 @@ class Footnote extends AbstractContainer */ public function __construct($paragraphStyle = null) { - $this->container = 'footnote'; $this->paragraphStyle = $this->setStyle(new Paragraph(), $paragraphStyle); } diff --git a/src/PhpWord/Element/Header.php b/src/PhpWord/Element/Header.php index be95936c..feaa86e8 100644 --- a/src/PhpWord/Element/Header.php +++ b/src/PhpWord/Element/Header.php @@ -22,13 +22,10 @@ namespace PhpOffice\PhpWord\Element; */ class Header extends Footer { - /** - * Container type - * - * @var string + * @var string Container type */ - protected $container = 'header'; + protected $container = 'Header'; /** * Add a Watermark Element diff --git a/src/PhpWord/Element/Image.php b/src/PhpWord/Element/Image.php index 6cfd6176..8e30b78c 100644 --- a/src/PhpWord/Element/Image.php +++ b/src/PhpWord/Element/Image.php @@ -19,7 +19,7 @@ namespace PhpOffice\PhpWord\Element; use PhpOffice\PhpWord\Exception\InvalidImageException; use PhpOffice\PhpWord\Exception\UnsupportedImageTypeException; -use PhpOffice\PhpWord\Settings; +use PhpOffice\PhpWord\Shared\ZipArchive; use PhpOffice\PhpWord\Style\Image as ImageStyle; /** @@ -283,6 +283,8 @@ class Image extends AbstractElement * Check memory image, supported type, image functions, and proportional width/height * * @param string $source + * @throws \PhpOffice\PhpWord\Exception\InvalidImageException + * @throws \PhpOffice\PhpWord\Exception\UnsupportedImageTypeException */ private function checkImage($source) { @@ -346,8 +348,7 @@ class Image extends AbstractElement list($zipFilename, $imageFilename) = explode('#', $source); $tempFilename = tempnam(sys_get_temp_dir(), 'PHPWordImage'); - $zipClass = Settings::getZipClass(); - $zip = new $zipClass(); + $zip = new ZipArchive(); if ($zip->open($zipFilename) !== false) { if ($zip->locateName($imageFilename)) { $imageContent = $zip->getFromName($imageFilename); diff --git a/src/PhpWord/Element/ListItem.php b/src/PhpWord/Element/ListItem.php index 1042362c..59bd8391 100644 --- a/src/PhpWord/Element/ListItem.php +++ b/src/PhpWord/Element/ListItem.php @@ -26,27 +26,26 @@ use PhpOffice\PhpWord\Style\ListItem as ListItemStyle; class ListItem extends AbstractElement { /** - * ListItem Style + * Element style * * @var \PhpOffice\PhpWord\Style\ListItem */ private $style; /** - * Textrun + * Text object * - * @var Text + * @var \PhpOffice\PhpWord\Element\Text */ private $textObject; /** - * ListItem Depth + * Depth * * @var int */ private $depth; - /** * Create a new ListItem * @@ -70,7 +69,9 @@ class ListItem extends AbstractElement } /** - * Get ListItem style + * Get style + * + * @return \PhpOffice\PhpWord\Style\ListItem */ public function getStyle() { @@ -78,7 +79,9 @@ class ListItem extends AbstractElement } /** - * Get ListItem TextRun + * Get Text object + * + * @return \PhpOffice\PhpWord\Element\Text */ public function getTextObject() { @@ -86,10 +89,23 @@ class ListItem extends AbstractElement } /** - * Get ListItem depth + * Get depth + * + * @return int */ public function getDepth() { return $this->depth; } + + /** + * Get text + * + * @return string + * @since 0.11.0 + */ + public function getText() + { + return $this->textObject->getText(); + } } diff --git a/src/PhpWord/Element/ListItemRun.php b/src/PhpWord/Element/ListItemRun.php index 1a52bd89..fb219f91 100644 --- a/src/PhpWord/Element/ListItemRun.php +++ b/src/PhpWord/Element/ListItemRun.php @@ -17,7 +17,6 @@ namespace PhpOffice\PhpWord\Element; -use PhpOffice\PhpWord\Shared\String; use PhpOffice\PhpWord\Style\ListItem as ListItemStyle; use PhpOffice\PhpWord\Style\Paragraph; @@ -26,6 +25,11 @@ use PhpOffice\PhpWord\Style\Paragraph; */ class ListItemRun extends TextRun { + /** + * @var string Container type + */ + protected $container = 'ListItemRun'; + /** * ListItem Style * @@ -44,13 +48,11 @@ class ListItemRun extends TextRun * Create a new ListItem * * @param int $depth - * @param mixed $fontStyle * @param array|string|null $listStyle * @param mixed $paragraphStyle */ - public function __construct($depth = 0, $fontStyle = null, $listStyle = null, $paragraphStyle = null) + public function __construct($depth = 0, $listStyle = null, $paragraphStyle = null) { - $this->container = 'listitemrun'; $this->depth = $depth; // Version >= 0.10.0 will pass numbering style name. Older version will use old method diff --git a/src/PhpWord/Element/Object.php b/src/PhpWord/Element/Object.php index a87da019..a63c1869 100644 --- a/src/PhpWord/Element/Object.php +++ b/src/PhpWord/Element/Object.php @@ -58,6 +58,7 @@ class Object extends AbstractElement * * @param string $source * @param mixed $style + * @throws \PhpOffice\PhpWord\Exception\InvalidObjectException */ public function __construct($source, $style = null) { diff --git a/src/PhpWord/Element/PreserveText.php b/src/PhpWord/Element/PreserveText.php index 004ffbc3..100385c9 100644 --- a/src/PhpWord/Element/PreserveText.php +++ b/src/PhpWord/Element/PreserveText.php @@ -54,7 +54,7 @@ class PreserveText extends AbstractElement * @param string $text * @param mixed $fontStyle * @param mixed $paragraphStyle - * @return $this + * @return self */ public function __construct($text = null, $fontStyle = null, $paragraphStyle = null) { diff --git a/src/PhpWord/Element/Row.php b/src/PhpWord/Element/Row.php index 0eb18784..07957ac1 100644 --- a/src/PhpWord/Element/Row.php +++ b/src/PhpWord/Element/Row.php @@ -43,21 +43,18 @@ class Row extends AbstractElement /** * Row cells * - * @var array + * @var \PhpOffice\PhpWord\Element\Cell[] */ private $cells = array(); /** * Create a new table row * - * @param string $docPart - * @param int $docPartId * @param int $height * @param mixed $style */ - public function __construct($docPart, $docPartId, $height = null, $style = null) + public function __construct($height = null, $style = null) { - $this->setDocPart($docPart, $docPartId); $this->height = $height; $this->style = $this->setStyle(new RowStyle(), $style, true); } @@ -67,19 +64,22 @@ class Row extends AbstractElement * * @param int $width * @param mixed $style + * @return \PhpOffice\PhpWord\Element\Cell */ public function addCell($width = null, $style = null) { - $cell = new Cell($this->getDocPart(), $this->getDocPartId(), $width, $style); + $cell = new Cell($width, $style); + $cell->setDocPart($this->getDocPart(), $this->getDocPartId()); $cell->setPhpWord($this->phpWord); $this->cells[] = $cell; + return $cell; } /** * Get all cells * - * @return array + * @return \PhpOffice\PhpWord\Element\Cell[] */ public function getCells() { diff --git a/src/PhpWord/Element/Section.php b/src/PhpWord/Element/Section.php index 04ff5aa2..b7cee6a2 100644 --- a/src/PhpWord/Element/Section.php +++ b/src/PhpWord/Element/Section.php @@ -18,7 +18,6 @@ namespace PhpOffice\PhpWord\Element; use PhpOffice\PhpWord\Exception\Exception; -use PhpOffice\PhpWord\PhpWord; use PhpOffice\PhpWord\Style\Section as SectionSettings; /** @@ -26,6 +25,11 @@ use PhpOffice\PhpWord\Style\Section as SectionSettings; */ class Section extends AbstractContainer { + /** + * @var string Container type + */ + protected $container = 'Section'; + /** * Section settings * @@ -55,7 +59,6 @@ class Section extends AbstractContainer */ public function __construct($sectionCount, $settings = null) { - $this->container = 'section'; $this->sectionId = $sectionCount; $this->setDocPart($this->container, $this->sectionId); $this->settings = new SectionSettings(); @@ -98,15 +101,7 @@ class Section extends AbstractContainer */ public function addTitle($text, $depth = 1) { - $title = new Title($text, $depth); - $title->setDocPart($this->getDocPart(), $this->getDocPartId()); - if ($this->phpWord instanceof PhpWord) { - $bookmarkId = $this->phpWord->addTitle($title); - $title->setBookmarkId($bookmarkId); - } - $this->addElement($title); - - return $title; + return $this->addElement('Title', $text, $depth); } /** @@ -114,7 +109,7 @@ class Section extends AbstractContainer */ public function addPageBreak() { - $this->addElement(new PageBreak()); + return $this->addElement('PageBreak'); } /** @@ -128,10 +123,7 @@ class Section extends AbstractContainer */ public function addTOC($fontStyle = null, $tocStyle = null, $minDepth = 1, $maxDepth = 9) { - $toc = new TOC($fontStyle, $tocStyle, $minDepth, $maxDepth); - $this->addElement($toc); - - return $toc; + return $this->addElement('TOC', $fontStyle, $tocStyle, $minDepth, $maxDepth); } /** @@ -214,6 +206,7 @@ class Section extends AbstractContainer if (in_array($type, array(Header::AUTO, Header::FIRST, Header::EVEN))) { $index = count($collection); + /** @var \PhpOffice\PhpWord\Element\AbstractContainer $container Type hint */ $container = new $containerClass($this->sectionId, ++$index, $type); $container->setPhpWord($this->phpWord); diff --git a/src/PhpWord/Element/TOC.php b/src/PhpWord/Element/TOC.php index 548f4f8a..9ac74554 100644 --- a/src/PhpWord/Element/TOC.php +++ b/src/PhpWord/Element/TOC.php @@ -95,6 +95,7 @@ class TOC extends AbstractElement $titles = $this->phpWord->getTitles()->getItems(); foreach ($titles as $i => $title) { + /** @var \PhpOffice\PhpWord\Element\Title $title Type hint */ $depth = $title->getDepth(); if ($this->minDepth > $depth) { unset($titles[$i]); diff --git a/src/PhpWord/Element/Table.php b/src/PhpWord/Element/Table.php index e87c591f..01d3d7c8 100644 --- a/src/PhpWord/Element/Table.php +++ b/src/PhpWord/Element/Table.php @@ -34,14 +34,14 @@ class Table extends AbstractElement /** * Table rows * - * @var array + * @var \PhpOffice\PhpWord\Element\Row[] */ private $rows = array(); /** * Table width * - * @var integer + * @var int */ private $width = null; @@ -59,35 +59,40 @@ class Table extends AbstractElement /** * Add a row * - * @param integer $height + * @param int $height * @param mixed $style + * @return \PhpOffice\PhpWord\Element\Row */ public function addRow($height = null, $style = null) { - $row = new Row($this->getDocPart(), $this->getDocPartId(), $height, $style); + $row = new Row($height, $style); + $row->setDocPart($this->getDocPart(), $this->getDocPartId()); $row->setPhpWord($this->phpWord); $this->rows[] = $row; + return $row; } /** * Add a cell * - * @param integer $width + * @param int $width * @param mixed $style - * @return Cell + * @return \PhpOffice\PhpWord\Element\Cell */ public function addCell($width = null, $style = null) { $index = count($this->rows) - 1; - $cell = $this->rows[$index]->addCell($width, $style); + $row = $this->rows[$index]; + $cell = $row->addCell($width, $style); + return $cell; } /** * Get all rows * - * @return array + * @return \PhpOffice\PhpWord\Element\Row[] */ public function getRows() { @@ -107,7 +112,7 @@ class Table extends AbstractElement /** * Set table width * - * @param integer $width + * @param int $width */ public function setWidth($width) { @@ -117,7 +122,7 @@ class Table extends AbstractElement /** * Get table width * - * @return integer + * @return int */ public function getWidth() { @@ -127,7 +132,7 @@ class Table extends AbstractElement /** * Get column count * - * @return integer + * @return int */ public function countColumns() { @@ -135,7 +140,9 @@ class Table extends AbstractElement if (is_array($this->rows)) { $rowCount = count($this->rows); for ($i = 0; $i < $rowCount; $i++) { - $cellCount = count($this->rows[$i]->getCells()); + /** @var \PhpOffice\PhpWord\Element\Row $row Type hint */ + $row = $this->rows[$i]; + $cellCount = count($row->getCells()); if ($columnCount < $cellCount) { $columnCount = $cellCount; } diff --git a/src/PhpWord/Element/TextBox.php b/src/PhpWord/Element/TextBox.php index c3c83d81..06c95181 100644 --- a/src/PhpWord/Element/TextBox.php +++ b/src/PhpWord/Element/TextBox.php @@ -26,6 +26,11 @@ use PhpOffice\PhpWord\Style\TextBox as TextBoxStyle; */ class TextBox extends AbstractContainer { + /** + * @var string Container type + */ + protected $container = 'TextBox'; + /** * TextBox style * @@ -40,7 +45,6 @@ class TextBox extends AbstractContainer */ public function __construct($style = null) { - $this->container = 'textbox'; $this->style = $this->setStyle(new TextBoxStyle(), $style); } diff --git a/src/PhpWord/Element/TextRun.php b/src/PhpWord/Element/TextRun.php index 6c8aa010..75837104 100644 --- a/src/PhpWord/Element/TextRun.php +++ b/src/PhpWord/Element/TextRun.php @@ -24,6 +24,11 @@ use PhpOffice\PhpWord\Style\Paragraph; */ class TextRun extends AbstractContainer { + /** + * @var string Container type + */ + protected $container = 'TextRun'; + /** * Paragraph style * @@ -38,7 +43,6 @@ class TextRun extends AbstractContainer */ public function __construct($paragraphStyle = null) { - $this->container = 'textrun'; $this->paragraphStyle = $this->setStyle(new Paragraph(), $paragraphStyle); } diff --git a/src/PhpWord/Element/Title.php b/src/PhpWord/Element/Title.php index 481f061b..d5206879 100644 --- a/src/PhpWord/Element/Title.php +++ b/src/PhpWord/Element/Title.php @@ -39,13 +39,6 @@ class Title extends AbstractElement */ private $depth = 1; - /** - * Title Bookmark ID - * - * @var int - */ - private $bookmarkId = 1; - /** * Name of the heading style, e.g. 'Heading1' * @@ -53,14 +46,6 @@ class Title extends AbstractElement */ private $style; - /** - * Title anchor - * - * @var int - * @deprecated 0.10.0 - */ - private $anchor; - /** * Create a new Title Element * @@ -79,26 +64,6 @@ class Title extends AbstractElement return $this; } - /** - * Set Bookmark ID - * - * @param int $bookmarkId - */ - public function setBookmarkId($bookmarkId) - { - $this->bookmarkId = $bookmarkId; - } - - /** - * Get Anchor - * - * @return int - */ - public function getBookmarkId() - { - return $this->bookmarkId; - } - /** * Get Title Text content * @@ -128,28 +93,4 @@ class Title extends AbstractElement { return $this->style; } - - /** - * Set Anchor - * - * @param int $anchor - * @deprecated 0.10.0 - * @codeCoverageIgnore - */ - public function setAnchor($anchor) - { - $this->anchor = $anchor; - } - - /** - * Get Anchor - * - * @return int - * @deprecated 0.10.0 - * @codeCoverageIgnore - */ - public function getAnchor() - { - return '_Toc' . (252634154 + $this->bookmarkId); - } } diff --git a/src/PhpWord/PhpWord.php b/src/PhpWord/PhpWord.php index 50890ad3..c54faa36 100644 --- a/src/PhpWord/PhpWord.php +++ b/src/PhpWord/PhpWord.php @@ -22,24 +22,22 @@ use PhpOffice\PhpWord\Collection\Footnotes; use PhpOffice\PhpWord\Collection\Titles; use PhpOffice\PhpWord\Element\Section; use PhpOffice\PhpWord\Exception\Exception; -use PhpOffice\PhpWord\Style; /** * PHPWord main class */ class PhpWord { - const DEFAULT_FONT_COLOR = '000000'; // HEX - const DEFAULT_FONT_CONTENT_TYPE = 'default'; // default|eastAsia|cs - const DEFAULT_FONT_NAME = 'Arial'; - /** - * Default font size, in points. + * Default font settings * - * OOXML defined font size values in halfpoints, i.e. twice of what PhpWord - * use, and the conversion will be conducted during XML writing. + * @const string|int + * @deprecated 0.11.0 Use Settings constants */ - const DEFAULT_FONT_SIZE = 10; + const DEFAULT_FONT_NAME = Settings::DEFAULT_FONT_NAME; + const DEFAULT_FONT_SIZE = Settings::DEFAULT_FONT_SIZE; + const DEFAULT_FONT_COLOR = Settings::DEFAULT_FONT_COLOR; + const DEFAULT_FONT_CONTENT_TYPE = Settings::DEFAULT_FONT_CONTENT_TYPE; /** * Document properties object @@ -76,19 +74,6 @@ class PhpWord */ private $endnotes; - /** - * Default font name - * - * @var string - */ - private $defaultFontName; - - /** - * Default font size - * @var int - */ - private $defaultFontSize; - /** * Create new */ @@ -98,8 +83,6 @@ class PhpWord $this->titles = new Titles(); $this->footnotes = new Footnotes(); $this->endnotes = new Endnotes(); - $this->defaultFontName = self::DEFAULT_FONT_NAME; - $this->defaultFontSize = self::DEFAULT_FONT_SIZE; } /** @@ -220,7 +203,7 @@ class PhpWord */ public function getDefaultFontName() { - return $this->defaultFontName; + return Settings::getDefaultFontName(); } /** @@ -230,7 +213,7 @@ class PhpWord */ public function setDefaultFontName($fontName) { - $this->defaultFontName = $fontName; + Settings::setDefaultFontName($fontName); } /** @@ -240,7 +223,7 @@ class PhpWord */ public function getDefaultFontSize() { - return $this->defaultFontSize; + return Settings::getDefaultFontSize(); } /** @@ -250,17 +233,18 @@ class PhpWord */ public function setDefaultFontSize($fontSize) { - $this->defaultFontSize = $fontSize; + Settings::setDefaultFontSize($fontSize); } /** * Set default paragraph style definition to styles.xml * * @param array $styles Paragraph style definition + * @return \PhpOffice\PhpWord\Style\Paragraph */ public function setDefaultParagraphStyle($styles) { - Style::setDefaultParagraphStyle($styles); + return Style::setDefaultParagraphStyle($styles); } /** @@ -268,10 +252,11 @@ class PhpWord * * @param string $styleName * @param array $styles + * @return \PhpOffice\PhpWord\Style\Paragraph */ public function addParagraphStyle($styleName, $styles) { - Style::addParagraphStyle($styleName, $styles); + return Style::addParagraphStyle($styleName, $styles); } /** @@ -280,10 +265,11 @@ class PhpWord * @param string $styleName * @param mixed $fontStyle * @param mixed $paragraphStyle + * @return \PhpOffice\PhpWord\Style\Font */ public function addFontStyle($styleName, $fontStyle, $paragraphStyle = null) { - Style::addFontStyle($styleName, $fontStyle, $paragraphStyle); + return Style::addFontStyle($styleName, $fontStyle, $paragraphStyle); } /** @@ -292,33 +278,11 @@ class PhpWord * @param string $styleName * @param mixed $styleTable * @param mixed $styleFirstRow + * @return \PhpOffice\PhpWord\Style\Table */ public function addTableStyle($styleName, $styleTable, $styleFirstRow = null) { - Style::addTableStyle($styleName, $styleTable, $styleFirstRow); - } - - /** - * Adds a heading style definition to styles.xml - * - * @param int $titleCount - * @param mixed $fontStyle - * @param mixed $paragraphStyle - */ - public function addTitleStyle($titleCount, $fontStyle, $paragraphStyle = null) - { - Style::addTitleStyle($titleCount, $fontStyle, $paragraphStyle); - } - - /** - * Adds a hyperlink style to styles.xml - * - * @param string $styleName - * @param mixed $styles - */ - public function addLinkStyle($styleName, $styles) - { - Style::addLinkStyle($styleName, $styles); + return Style::addTableStyle($styleName, $styleTable, $styleFirstRow); } /** @@ -326,10 +290,36 @@ class PhpWord * * @param string $styleName * @param mixed $styles + * @return \PhpOffice\PhpWord\Style\Numbering */ public function addNumberingStyle($styleName, $styles) { - Style::addNumberingStyle($styleName, $styles); + return Style::addNumberingStyle($styleName, $styles); + } + + /** + * Adds a hyperlink style to styles.xml + * + * @param string $styleName + * @param mixed $styles + * @return \PhpOffice\PhpWord\Style\Font + */ + public function addLinkStyle($styleName, $styles) + { + return Style::addLinkStyle($styleName, $styles); + } + + /** + * Adds a heading style definition to styles.xml + * + * @param int $depth + * @param mixed $fontStyle + * @param mixed $paragraphStyle + * @return \PhpOffice\PhpWord\Style\Font + */ + public function addTitleStyle($depth, $fontStyle, $paragraphStyle = null) + { + return Style::addTitleStyle($depth, $fontStyle, $paragraphStyle); } /** diff --git a/src/PhpWord/Reader/AbstractReader.php b/src/PhpWord/Reader/AbstractReader.php index 73d18666..a243c5d2 100644 --- a/src/PhpWord/Reader/AbstractReader.php +++ b/src/PhpWord/Reader/AbstractReader.php @@ -54,47 +54,47 @@ abstract class AbstractReader implements ReaderInterface /** * Set read data only * - * @param bool $pValue + * @param bool $value * @return self */ - public function setReadDataOnly($pValue = true) + public function setReadDataOnly($value = true) { - $this->readDataOnly = $pValue; + $this->readDataOnly = $value; return $this; } /** * Open file for reading * - * @param string $pFilename + * @param string $filename * @return resource * @throws \PhpOffice\PhpWord\Exception\Exception */ - protected function openFile($pFilename) + protected function openFile($filename) { // Check if file exists - if (!file_exists($pFilename) || !is_readable($pFilename)) { - throw new Exception("Could not open " . $pFilename . " for reading! File does not exist."); + if (!file_exists($filename) || !is_readable($filename)) { + throw new Exception("Could not open " . $filename . " for reading! File does not exist."); } // Open file - $this->fileHandle = fopen($pFilename, 'r'); + $this->fileHandle = fopen($filename, 'r'); if ($this->fileHandle === false) { - throw new Exception("Could not open file " . $pFilename . " for reading."); + throw new Exception("Could not open file " . $filename . " for reading."); } } /** * Can the current ReaderInterface read the file? * - * @param string $pFilename + * @param string $filename * @return bool */ - public function canRead($pFilename) + public function canRead($filename) { // Check if file exists try { - $this->openFile($pFilename); + $this->openFile($filename); } catch (Exception $e) { return false; } diff --git a/src/PhpWord/Reader/ODText.php b/src/PhpWord/Reader/ODText.php index 06327254..19efdc51 100644 --- a/src/PhpWord/Reader/ODText.php +++ b/src/PhpWord/Reader/ODText.php @@ -40,6 +40,7 @@ class ODText extends AbstractReader implements ReaderInterface $readerParts = array( 'content.xml' => 'Content', + 'meta.xml' => 'Meta', ); foreach ($readerParts as $xmlFile => $partName) { @@ -62,6 +63,7 @@ class ODText extends AbstractReader implements ReaderInterface { $partClass = "PhpOffice\\PhpWord\\Reader\\ODText\\{$partName}"; if (class_exists($partClass)) { + /** @var \PhpOffice\PhpWord\Reader\ODText\AbstractPart $part Type hint */ $part = new $partClass($docFile, $xmlFile); $part->setRels($relationships); $part->read($phpWord); diff --git a/src/PhpWord/Reader/ODText/AbstractPart.php b/src/PhpWord/Reader/ODText/AbstractPart.php index 8ffb9f1b..815e60fd 100644 --- a/src/PhpWord/Reader/ODText/AbstractPart.php +++ b/src/PhpWord/Reader/ODText/AbstractPart.php @@ -17,16 +17,33 @@ namespace PhpOffice\PhpWord\Reader\ODText; +use PhpOffice\PhpWord\Reader\Word2007\AbstractPart as Word2007AbstractPart; use PhpOffice\PhpWord\Shared\XMLReader; /** * Abstract part reader */ -abstract class AbstractPart extends \PhpOffice\PhpWord\Reader\Word2007\AbstractPart +abstract class AbstractPart extends Word2007AbstractPart { + /** + * Read w:p (override) + * + * @param \PhpOffice\PhpWord\Shared\XMLReader $xmlReader + * @param \DOMElement $domNode + * @param mixed $parent + * @param string $docPart + * + * @todo Get font style for preserve text + */ + protected function readParagraph(XMLReader $xmlReader, \DOMElement $domNode, &$parent, $docPart) + { + } + /** * Read w:r (override) * + * @param \PhpOffice\PhpWord\Shared\XMLReader $xmlReader + * @param \DOMElement $domNode * @param mixed $parent * @param string $docPart * @param mixed $paragraphStyle @@ -35,6 +52,18 @@ abstract class AbstractPart extends \PhpOffice\PhpWord\Reader\Word2007\AbstractP { } + /** + * Read w:tbl (override) + * + * @param \PhpOffice\PhpWord\Shared\XMLReader $xmlReader + * @param \DOMElement $domNode + * @param mixed $parent + * @param string $docPart + */ + protected function readTable(XMLReader $xmlReader, \DOMElement $domNode, &$parent, $docPart) + { + } + /** * Read w:pPr (override) */ @@ -55,4 +84,16 @@ abstract class AbstractPart extends \PhpOffice\PhpWord\Reader\Word2007\AbstractP protected function readTableStyle(XMLReader $xmlReader, \DOMElement $domNode) { } + + /** + * Read style definition (override) + * + * @param \PhpOffice\PhpWord\Shared\XMLReader $xmlReader + * @param \DOMElement $parentNode + * @param array $styleDefs + * @return array + */ + protected function readStyleDefs(XMLReader $xmlReader, \DOMElement $parentNode = null, $styleDefs = array()) + { + } } diff --git a/src/PhpWord/Reader/ODText/Content.php b/src/PhpWord/Reader/ODText/Content.php index d2195679..12b39f74 100644 --- a/src/PhpWord/Reader/ODText/Content.php +++ b/src/PhpWord/Reader/ODText/Content.php @@ -22,6 +22,8 @@ use PhpOffice\PhpWord\Shared\XMLReader; /** * Content reader + * + * @since 0.10.0 */ class Content extends AbstractPart { diff --git a/src/PhpWord/Reader/ODText/Meta.php b/src/PhpWord/Reader/ODText/Meta.php new file mode 100644 index 00000000..f7f4542d --- /dev/null +++ b/src/PhpWord/Reader/ODText/Meta.php @@ -0,0 +1,79 @@ +getDomFromZip($this->docFile, $this->xmlFile); + $docProps = $phpWord->getDocumentProperties(); + + $metaNode = $xmlReader->getElement('office:meta'); + + // Standard properties + $properties = array( + 'title' => 'dc:title', + 'subject' => 'dc:subject', + 'description' => 'dc:description', + 'keywords' => 'meta:keyword', + 'creator' => 'meta:initial-creator', + 'lastModifiedBy' => 'dc:creator', + // 'created' => 'meta:creation-date', + // 'modified' => 'dc:date', + ); + foreach ($properties as $property => $path) { + $method = "set{$property}"; + $propertyNode = $xmlReader->getElement($path, $metaNode); + if ($propertyNode !== null && method_exists($docProps, $method)) { + $docProps->$method($propertyNode->nodeValue); + } + } + + // Custom properties + $propertyNodes = $xmlReader->getElements('meta:user-defined', $metaNode); + foreach ($propertyNodes as $propertyNode) { + $property = $xmlReader->getAttribute('meta:name', $propertyNode); + + // Set category, company, and manager property + if (in_array($property, array('Category', 'Company', 'Manager'))) { + $method = "set{$property}"; + $docProps->$method($propertyNode->nodeValue); + + // Set other custom properties + } else { + $docProps->setCustomProperty($property, $propertyNode->nodeValue); + } + } + } +} diff --git a/src/PhpWord/Reader/ReaderInterface.php b/src/PhpWord/Reader/ReaderInterface.php index f207aa6f..df663197 100644 --- a/src/PhpWord/Reader/ReaderInterface.php +++ b/src/PhpWord/Reader/ReaderInterface.php @@ -25,15 +25,15 @@ interface ReaderInterface /** * Can the current ReaderInterface read the file? * - * @param string $pFilename + * @param string $filename * @return boolean */ - public function canRead($pFilename); + public function canRead($filename); /** * Loads PhpWord from file * - * @param string $pFilename + * @param string $filename */ - public function load($pFilename); + public function load($filename); } diff --git a/src/PhpWord/Reader/Word2007.php b/src/PhpWord/Reader/Word2007.php index c792a283..70d5f60b 100644 --- a/src/PhpWord/Reader/Word2007.php +++ b/src/PhpWord/Reader/Word2007.php @@ -18,8 +18,8 @@ namespace PhpOffice\PhpWord\Reader; use PhpOffice\PhpWord\PhpWord; -use PhpOffice\PhpWord\Settings; use PhpOffice\PhpWord\Shared\XMLReader; +use PhpOffice\PhpWord\Shared\ZipArchive; /** * Reader for Word2007 @@ -87,6 +87,7 @@ class Word2007 extends AbstractReader implements ReaderInterface { $partClass = "PhpOffice\\PhpWord\\Reader\\Word2007\\{$partName}"; if (class_exists($partClass)) { + /** @var \PhpOffice\PhpWord\Reader\Word2007\AbstractPart $part Type hint */ $part = new $partClass($docFile, $xmlFile); $part->setRels($relationships); $part->read($phpWord); @@ -109,8 +110,7 @@ class Word2007 extends AbstractReader implements ReaderInterface // word/_rels/*.xml.rels $wordRelsPath = 'word/_rels/'; - $zipClass = Settings::getZipClass(); - $zip = new $zipClass(); + $zip = new ZipArchive(); if ($zip->open($docFile) === true) { for ($i = 0; $i < $zip->numFiles; $i++) { $xmlFile = $zip->getNameIndex($i); diff --git a/src/PhpWord/Reader/Word2007/AbstractPart.php b/src/PhpWord/Reader/Word2007/AbstractPart.php index a6efb329..9a0e0c63 100644 --- a/src/PhpWord/Reader/Word2007/AbstractPart.php +++ b/src/PhpWord/Reader/Word2007/AbstractPart.php @@ -22,9 +22,22 @@ use PhpOffice\PhpWord\Shared\XMLReader; /** * Abstract part reader + * + * This class is inherited by ODText reader */ abstract class AbstractPart { + /** + * Conversion method + * + * @const int + */ + const READ_VALUE = 'attributeValue'; // Read attribute value + const READ_EQUAL = 'attributeEquals'; // Read `true` when attribute value equals specified value + const READ_TRUE = 'attributeTrue'; // Read `true` when element exists + const READ_FALSE = 'attributeFalse'; // Read `false` when element exists + const READ_SIZE = 'attributeMultiplyByTwo'; // Read special attribute value for Font::$size + /** * Document file * @@ -73,6 +86,96 @@ abstract class AbstractPart $this->rels = $value; } + /** + * Read w:p + * + * @param \PhpOffice\PhpWord\Shared\XMLReader $xmlReader + * @param \DOMElement $domNode + * @param mixed $parent + * @param string $docPart + * + * @todo Get font style for preserve text + */ + protected function readParagraph(XMLReader $xmlReader, \DOMElement $domNode, &$parent, $docPart) + { + // Paragraph style + $paragraphStyle = null; + $headingMatches = array(); + if ($xmlReader->elementExists('w:pPr', $domNode)) { + $paragraphStyle = $this->readParagraphStyle($xmlReader, $domNode); + if (is_array($paragraphStyle) && array_key_exists('styleName', $paragraphStyle)) { + preg_match('/Heading(\d)/', $paragraphStyle['styleName'], $headingMatches); + } + } + + // PreserveText + if ($xmlReader->elementExists('w:r/w:instrText', $domNode)) { + $ignoreText = false; + $textContent = ''; + $fontStyle = $this->readFontStyle($xmlReader, $domNode); + $nodes = $xmlReader->getElements('w:r', $domNode); + foreach ($nodes as $node) { + $instrText = $xmlReader->getValue('w:instrText', $node); + if ($xmlReader->elementExists('w:fldChar', $node)) { + $fldCharType = $xmlReader->getAttribute('w:fldCharType', $node, 'w:fldChar'); + if ($fldCharType == 'begin') { + $ignoreText = true; + } elseif ($fldCharType == 'end') { + $ignoreText = false; + } + } + if (!is_null($instrText)) { + $textContent .= '{' . $instrText . '}'; + } else { + if ($ignoreText === false) { + $textContent .= $xmlReader->getValue('w:t', $node); + } + } + } + $parent->addPreserveText($textContent, $fontStyle, $paragraphStyle); + + // List item + } elseif ($xmlReader->elementExists('w:pPr/w:numPr', $domNode)) { + $textContent = ''; + $numId = $xmlReader->getAttribute('w:val', $domNode, 'w:pPr/w:numPr/w:numId'); + $levelId = $xmlReader->getAttribute('w:val', $domNode, 'w:pPr/w:numPr/w:ilvl'); + $nodes = $xmlReader->getElements('w:r', $domNode); + foreach ($nodes as $node) { + $textContent .= $xmlReader->getValue('w:t', $node); + } + $parent->addListItem($textContent, $levelId, null, "PHPWordList{$numId}", $paragraphStyle); + + // Heading + } elseif (!empty($headingMatches)) { + $textContent = ''; + $nodes = $xmlReader->getElements('w:r', $domNode); + foreach ($nodes as $node) { + $textContent .= $xmlReader->getValue('w:t', $node); + } + $parent->addTitle($textContent, $headingMatches[1]); + + // Text and TextRun + } else { + $runCount = $xmlReader->countElements('w:r', $domNode); + $linkCount = $xmlReader->countElements('w:hyperlink', $domNode); + $runLinkCount = $runCount + $linkCount; + if ($runLinkCount == 0) { + $parent->addTextBreak(null, $paragraphStyle); + } else { + if ($runLinkCount > 1) { + $textrun = $parent->addTextRun($paragraphStyle); + $textParent = &$textrun; + } else { + $textParent = &$parent; + } + $nodes = $xmlReader->getElements('*', $domNode); + foreach ($nodes as $node) { + $this->readRun($xmlReader, $node, $textParent, $docPart, $paragraphStyle); + } + } + } + } + /** * Read w:r * @@ -135,143 +238,145 @@ abstract class AbstractPart } } + /** + * Read w:tbl + * + * @param \PhpOffice\PhpWord\Shared\XMLReader $xmlReader + * @param \DOMElement $domNode + * @param mixed $parent + * @param string $docPart + */ + protected function readTable(XMLReader $xmlReader, \DOMElement $domNode, &$parent, $docPart) + { + // Table style + $tblStyle = null; + if ($xmlReader->elementExists('w:tblPr', $domNode)) { + $tblStyle = $this->readTableStyle($xmlReader, $domNode); + } + + /** @var \PhpOffice\PhpWord\Element\Table $table Type hint */ + $table = $parent->addTable($tblStyle); + $tblNodes = $xmlReader->getElements('*', $domNode); + foreach ($tblNodes as $tblNode) { + if ($tblNode->nodeName == 'w:tblGrid') { // Column + // @todo Do something with table columns + + } elseif ($tblNode->nodeName == 'w:tr') { // Row + $rowHeight = $xmlReader->getAttribute('w:val', $tblNode, 'w:trPr/w:trHeight'); + $rowHRule = $xmlReader->getAttribute('w:hRule', $tblNode, 'w:trPr/w:trHeight'); + $rowHRule = $rowHRule == 'exact' ? true : false; + $rowStyle = array( + 'tblHeader' => $xmlReader->elementExists('w:trPr/w:tblHeader', $tblNode), + 'cantSplit' => $xmlReader->elementExists('w:trPr/w:cantSplit', $tblNode), + 'exactHeight' => $rowHRule, + ); + + $row = $table->addRow($rowHeight, $rowStyle); + $rowNodes = $xmlReader->getElements('*', $tblNode); + foreach ($rowNodes as $rowNode) { + if ($rowNode->nodeName == 'w:trPr') { // Row style + // @todo Do something with row style + + } elseif ($rowNode->nodeName == 'w:tc') { // Cell + $cellWidth = $xmlReader->getAttribute('w:w', $rowNode, 'w:tcPr/w:tcW'); + $cellStyle = null; + $cellStyleNode = $xmlReader->getElement('w:tcPr', $rowNode); + if (!is_null($cellStyleNode)) { + $cellStyle = $this->readCellStyle($xmlReader, $cellStyleNode); + } + + $cell = $row->addCell($cellWidth, $cellStyle); + $cellNodes = $xmlReader->getElements('*', $rowNode); + foreach ($cellNodes as $cellNode) { + if ($cellNode->nodeName == 'w:p') { // Paragraph + $this->readParagraph($xmlReader, $cellNode, $cell, $docPart); + } + } + } + } + } + } + } + /** * Read w:pPr * + * @param \PhpOffice\PhpWord\Shared\XMLReader $xmlReader + * @param \DOMElement $domNode * @return array|null */ protected function readParagraphStyle(XMLReader $xmlReader, \DOMElement $domNode) { if (!$xmlReader->elementExists('w:pPr', $domNode)) { - return; + return null; } - $style = array(); - $mapping = array( - 'w:pStyle' => 'styleName', - 'w:ind' => 'indent', 'w:spacing' => 'spacing', - 'w:jc' => 'align', 'w:basedOn' => 'basedOn', 'w:next' => 'next', - 'w:widowControl' => 'widowControl', 'w:keepNext' => 'keepNext', - 'w:keepLines' => 'keepLines', 'w:pageBreakBefore' => 'pageBreakBefore', + $styleNode = $xmlReader->getElement('w:pPr', $domNode); + $styleDefs = array( + 'styleName' => array(self::READ_VALUE, 'w:pStyle'), + 'align' => array(self::READ_VALUE, 'w:jc'), + 'basedOn' => array(self::READ_VALUE, 'w:basedOn'), + 'next' => array(self::READ_VALUE, 'w:next'), + 'indent' => array(self::READ_VALUE, 'w:ind', 'w:left'), + 'hanging' => array(self::READ_VALUE, 'w:ind', 'w:hanging'), + 'spaceAfter' => array(self::READ_VALUE, 'w:spacing', 'w:after'), + 'spaceBefore' => array(self::READ_VALUE, 'w:spacing', 'w:before'), + 'widowControl' => array(self::READ_FALSE, 'w:widowControl'), + 'keepNext' => array(self::READ_TRUE, 'w:keepNext'), + 'keepLines' => array(self::READ_TRUE, 'w:keepLines'), + 'pageBreakBefore' => array(self::READ_TRUE, 'w:pageBreakBefore'), ); - $nodes = $xmlReader->getElements('w:pPr/*', $domNode); - foreach ($nodes as $node) { - if (!array_key_exists($node->nodeName, $mapping)) { - continue; - } - $property = $mapping[$node->nodeName]; - switch ($node->nodeName) { - - case 'w:ind': - $style['indent'] = $xmlReader->getAttribute('w:left', $node); - $style['hanging'] = $xmlReader->getAttribute('w:hanging', $node); - break; - - case 'w:spacing': - $style['spaceAfter'] = $xmlReader->getAttribute('w:after', $node); - $style['spaceBefore'] = $xmlReader->getAttribute('w:before', $node); - // Commented. Need to adjust the number when return value is null - // $style['spacing'] = $xmlReader->getAttribute('w:line', $node); - break; - - case 'w:keepNext': - case 'w:keepLines': - case 'w:pageBreakBefore': - $style[$property] = true; - break; - - case 'w:widowControl': - $style[$property] = false; - break; - - case 'w:pStyle': - case 'w:jc': - case 'w:basedOn': - case 'w:next': - $style[$property] = $xmlReader->getAttribute('w:val', $node); - break; - } - } - - return $style; + return $this->readStyleDefs($xmlReader, $styleNode, $styleDefs); } /** * Read w:rPr * - * @return array|null + * @param \PhpOffice\PhpWord\Shared\XMLReader $xmlReader + * @param \DOMElement $domNode + * @return array */ protected function readFontStyle(XMLReader $xmlReader, \DOMElement $domNode) { if (is_null($domNode)) { - return; + return null; } // Hyperlink has an extra w:r child if ($domNode->nodeName == 'w:hyperlink') { $domNode = $xmlReader->getElement('w:r', $domNode); } if (!$xmlReader->elementExists('w:rPr', $domNode)) { - return; + return null; } - $style = array(); - $mapping = array( - 'w:rStyle' => 'styleName', - 'w:b' => 'bold', 'w:i' => 'italic', 'w:color' => 'color', - 'w:strike' => 'strikethrough', 'w:u' => 'underline', - 'w:highlight' => 'fgColor', 'w:sz' => 'size', - 'w:rFonts' => 'name', 'w:vertAlign' => 'superScript', + $styleNode = $xmlReader->getElement('w:rPr', $domNode); + $styleDefs = array( + 'styleName' => array(self::READ_VALUE, 'w:rStyle'), + 'name' => array(self::READ_VALUE, 'w:rFonts', 'w:ascii'), + 'hint' => array(self::READ_VALUE, 'w:rFonts', 'w:hint'), + 'size' => array(self::READ_SIZE, 'w:sz'), + 'color' => array(self::READ_VALUE, 'w:color'), + 'underline' => array(self::READ_VALUE, 'w:u'), + 'bold' => array(self::READ_TRUE, 'w:b'), + 'italic' => array(self::READ_TRUE, 'w:i'), + 'strikethrough' => array(self::READ_TRUE, 'w:strike'), + 'doubleStrikethrough' => array(self::READ_TRUE, 'w:dstrike'), + 'smallCaps' => array(self::READ_TRUE, 'w:smallCaps'), + 'allCaps' => array(self::READ_TRUE, 'w:caps'), + 'superScript' => array(self::READ_EQUAL, 'w:vertAlign', 'w:val', 'superscript'), + 'subScript' => array(self::READ_EQUAL, 'w:vertAlign', 'w:val', 'subscript'), + 'fgColor' => array(self::READ_VALUE, 'w:highlight'), ); - $nodes = $xmlReader->getElements('w:rPr/*', $domNode); - foreach ($nodes as $node) { - if (!array_key_exists($node->nodeName, $mapping)) { - continue; - } - $property = $mapping[$node->nodeName]; - switch ($node->nodeName) { - - case 'w:rFonts': - $style['name'] = $xmlReader->getAttribute('w:ascii', $node); - $style['hint'] = $xmlReader->getAttribute('w:hint', $node); - break; - - case 'w:b': - case 'w:i': - case 'w:strike': - $style[$property] = true; - break; - - case 'w:rStyle': - case 'w:u': - case 'w:highlight': - case 'w:color': - $style[$property] = $xmlReader->getAttribute('w:val', $node); - break; - - case 'w:sz': - $style[$property] = $xmlReader->getAttribute('w:val', $node) / 2; - break; - - case 'w:vertAlign': - $style[$property] = $xmlReader->getAttribute('w:val', $node); - if ($style[$property] == 'superscript') { - $style['superScript'] = true; - } else { - $style['superScript'] = false; - $style['subScript'] = true; - } - break; - } - } - - return $style; + return $this->readStyleDefs($xmlReader, $styleNode, $styleDefs); } /** * Read w:tblPr * + * @param \PhpOffice\PhpWord\Shared\XMLReader $xmlReader + * @param \DOMElement $domNode * @return string|array|null * @todo Capture w:tblStylePr w:type="firstRow" */ @@ -285,42 +390,85 @@ abstract class AbstractPart if ($xmlReader->elementExists('w:tblPr/w:tblStyle', $domNode)) { $style = $xmlReader->getAttribute('w:val', $domNode, 'w:tblPr/w:tblStyle'); } else { - $style = array(); - $mapping = array( - 'w:tblCellMar' => 'cellMargin', - 'w:tblBorders' => 'border', - ); - - $nodes = $xmlReader->getElements('w:tblPr/*', $domNode); - foreach ($nodes as $node) { - if (!array_key_exists($node->nodeName, $mapping)) { - continue; - } - // $property = $mapping[$node->nodeName]; - switch ($node->nodeName) { - - case 'w:tblCellMar': - foreach ($margins as $side) { - $ucfSide = ucfirst($side); - $style["cellMargin$ucfSide"] = $xmlReader->getAttribute('w:w', $node, "w:$side"); - } - break; - - case 'w:tblBorders': - foreach ($borders as $side) { - $ucfSide = ucfirst($side); - $style["border{$ucfSide}Size"] = $xmlReader->getAttribute('w:sz', $node, "w:$side"); - $style["border{$ucfSide}Color"] = $xmlReader->getAttribute('w:color', $node, "w:$side"); - } - break; - } + $styleNode = $xmlReader->getElement('w:tblPr', $domNode); + $styleDefs = array(); + // $styleDefs['styleName'] = array(self::READ_VALUE, 'w:tblStyle'); + foreach ($margins as $side) { + $ucfSide = ucfirst($side); + $styleDefs["cellMargin$ucfSide"] = array(self::READ_VALUE, "w:tblCellMar/w:$side", 'w:w'); } + foreach ($borders as $side) { + $ucfSide = ucfirst($side); + $styleDefs["border{$ucfSide}Size"] = array(self::READ_VALUE, "w:tblBorders/w:$side", 'w:sz'); + $styleDefs["border{$ucfSide}Color"] = array(self::READ_VALUE, "w:tblBorders/w:$side", 'w:color'); + } + $style = $this->readStyleDefs($xmlReader, $styleNode, $styleDefs); } } return $style; } + /** + * Read w:tcPr + * + * @param \PhpOffice\PhpWord\Shared\XMLReader $xmlReader + * @param \DOMElement $domNode + * @return array + */ + private function readCellStyle(XMLReader $xmlReader, \DOMElement $domNode) + { + $styleDefs = array( + 'valign' => array(self::READ_VALUE, 'w:vAlign'), + 'textDirection' => array(self::READ_VALUE, 'w:textDirection'), + 'gridSpan' => array(self::READ_VALUE, 'w:gridSpan'), + 'vMerge' => array(self::READ_VALUE, 'w:vMerge'), + 'bgColor' => array(self::READ_VALUE, 'w:shd/w:fill'), + ); + + return $this->readStyleDefs($xmlReader, $domNode, $styleDefs); + } + + /** + * Read style definition + * + * @param \PhpOffice\PhpWord\Shared\XMLReader $xmlReader + * @param \DOMElement $parentNode + * @param array $styleDefs + * @return array + */ + protected function readStyleDefs(XMLReader $xmlReader, \DOMElement $parentNode = null, $styleDefs = array()) + { + $styles = array(); + + foreach ($styleDefs as $styleProp => $styleVal) { + @list($method, $element, $attribute, $expected) = $styleVal; + + if ($xmlReader->elementExists($element, $parentNode)) { + $node = $xmlReader->getElement($element, $parentNode); + + // Use w:val as default if no attribute assigned + $attribute = ($attribute === null) ? 'w:val' : $attribute; + $attributeValue = $xmlReader->getAttribute($attribute, $node); + + // Assign style value based on conversion model + if ($method == self::READ_VALUE) { + $styles[$styleProp] = $attributeValue; + } elseif ($method == self::READ_SIZE) { + $styles[$styleProp] = $attributeValue / 2; + } elseif ($method == self::READ_TRUE) { + $styles[$styleProp] = true; + } elseif ($method == self::READ_FALSE) { + $styles[$styleProp] = false; + } elseif ($method == self::READ_EQUAL && $attributeValue == $expected) { + $styles[$styleProp] = true; + } + } + } + + return $styles; + } + /** * Returns the target of image, object, or link as stored in ::readMainRels * diff --git a/src/PhpWord/Reader/Word2007/Document.php b/src/PhpWord/Reader/Word2007/Document.php index d38b3fb9..3ac4e0eb 100644 --- a/src/PhpWord/Reader/Word2007/Document.php +++ b/src/PhpWord/Reader/Word2007/Document.php @@ -56,9 +56,7 @@ class Document extends AbstractPart if (!is_null($settingsNode)) { $settings = $this->readSectionStyle($xmlReader, $settingsNode); $section->setSettings($settings); - if (!is_null($settings)) { - $this->readHeaderFooter($settings, $section); - } + $this->readHeaderFooter($settings, $section); } $section = $phpWord->addSection(); } @@ -71,9 +69,7 @@ class Document extends AbstractPart case 'w:sectPr': // Last section $settings = $this->readSectionStyle($xmlReader, $node); $section->setSettings($settings); - if (!is_null($settings)) { - $this->readHeaderFooter($settings, $section); - } + $this->readHeaderFooter($settings, $section); break; } } @@ -118,241 +114,45 @@ class Document extends AbstractPart } } - /** - * Read w:p - * - * @param mixed $parent - * @param string $docPart - * - * @todo Get font style for preserve text - */ - private function readParagraph(XMLReader $xmlReader, \DOMElement $domNode, &$parent, $docPart) - { - // Paragraph style - $paragraphStyle = null; - $headingMatches = array(); - if ($xmlReader->elementExists('w:pPr', $domNode)) { - $paragraphStyle = $this->readParagraphStyle($xmlReader, $domNode); - if (is_array($paragraphStyle) && array_key_exists('styleName', $paragraphStyle)) { - preg_match('/Heading(\d)/', $paragraphStyle['styleName'], $headingMatches); - } - } - - // PreserveText - if ($xmlReader->elementExists('w:r/w:instrText', $domNode)) { - $ignoreText = false; - $textContent = ''; - $fontStyle = $this->readFontStyle($xmlReader, $domNode); - $nodes = $xmlReader->getElements('w:r', $domNode); - foreach ($nodes as $node) { - $instrText = $xmlReader->getValue('w:instrText', $node); - if ($xmlReader->elementExists('w:fldChar', $node)) { - $fldCharType = $xmlReader->getAttribute('w:fldCharType', $node, 'w:fldChar'); - if ($fldCharType == 'begin') { - $ignoreText = true; - } elseif ($fldCharType == 'end') { - $ignoreText = false; - } - } - if (!is_null($instrText)) { - $textContent .= '{' . $instrText . '}'; - } else { - if ($ignoreText === false) { - $textContent .= $xmlReader->getValue('w:t', $node); - } - } - } - $parent->addPreserveText($textContent, $fontStyle, $paragraphStyle); - - // List item - } elseif ($xmlReader->elementExists('w:pPr/w:numPr', $domNode)) { - $textContent = ''; - $numId = $xmlReader->getAttribute('w:val', $domNode, 'w:pPr/w:numPr/w:numId'); - $levelId = $xmlReader->getAttribute('w:val', $domNode, 'w:pPr/w:numPr/w:ilvl'); - $nodes = $xmlReader->getElements('w:r', $domNode); - foreach ($nodes as $node) { - $textContent .= $xmlReader->getValue('w:t', $node); - } - $parent->addListItem($textContent, $levelId, null, "PHPWordList{$numId}", $paragraphStyle); - - // Heading - } elseif (!empty($headingMatches)) { - $textContent = ''; - $nodes = $xmlReader->getElements('w:r', $domNode); - foreach ($nodes as $node) { - $textContent .= $xmlReader->getValue('w:t', $node); - } - $parent->addTitle($textContent, $headingMatches[1]); - - // Text and TextRun - } else { - $runCount = $xmlReader->countElements('w:r', $domNode); - $linkCount = $xmlReader->countElements('w:hyperlink', $domNode); - $runLinkCount = $runCount + $linkCount; - if ($runLinkCount == 0) { - $parent->addTextBreak(null, $paragraphStyle); - } else { - if ($runLinkCount > 1) { - $textrun = $parent->addTextRun($paragraphStyle); - $textParent = &$textrun; - } else { - $textParent = &$parent; - } - $nodes = $xmlReader->getElements('*', $domNode); - foreach ($nodes as $node) { - $this->readRun($xmlReader, $node, $textParent, $docPart, $paragraphStyle); - } - } - } - } - - /** - * Read w:tbl - * - * @param mixed $parent - * @param string $docPart - */ - private function readTable(XMLReader $xmlReader, \DOMElement $domNode, &$parent, $docPart) - { - // Table style - $tblStyle = null; - if ($xmlReader->elementExists('w:tblPr', $domNode)) { - $tblStyle = $this->readTableStyle($xmlReader, $domNode); - } - - $table = $parent->addTable($tblStyle); - $tblNodes = $xmlReader->getElements('*', $domNode); - foreach ($tblNodes as $tblNode) { - if ($tblNode->nodeName == 'w:tblGrid') { // Column - // @todo Do something with table columns - - } elseif ($tblNode->nodeName == 'w:tr') { // Row - $rowHeight = $xmlReader->getAttribute('w:val', $tblNode, 'w:trPr/w:trHeight'); - $rowHRule = $xmlReader->getAttribute('w:hRule', $tblNode, 'w:trPr/w:trHeight'); - $rowHRule = $rowHRule == 'exact' ? true : false; - $rowStyle = array( - 'tblHeader' => $xmlReader->elementExists('w:trPr/w:tblHeader', $tblNode), - 'cantSplit' => $xmlReader->elementExists('w:trPr/w:cantSplit', $tblNode), - 'exactHeight' => $rowHRule, - ); - - $row = $table->addRow($rowHeight, $rowStyle); - $rowNodes = $xmlReader->getElements('*', $tblNode); - foreach ($rowNodes as $rowNode) { - if ($rowNode->nodeName == 'w:trPr') { // Row style - // @todo Do something with row style - - } elseif ($rowNode->nodeName == 'w:tc') { // Cell - $cellWidth = $xmlReader->getAttribute('w:w', $rowNode, 'w:tcPr/w:tcW'); - $cellStyle = null; - $cellStyleNode = $xmlReader->getElement('w:tcPr', $rowNode); - if (!is_null($cellStyleNode)) { - $cellStyle = $this->readCellStyle($xmlReader, $cellStyleNode); - } - - $cell = $row->addCell($cellWidth, $cellStyle); - $cellNodes = $xmlReader->getElements('*', $rowNode); - foreach ($cellNodes as $cellNode) { - if ($cellNode->nodeName == 'w:p') { // Paragraph - $this->readParagraph($xmlReader, $cellNode, $cell, $docPart); - } - } - } - } - } - } - } - /** * Read w:sectPr * - * @return array|null + * @param \PhpOffice\PhpWord\Shared\XMLReader $xmlReader + * @param \DOMElement $domNode + * @return array */ private function readSectionStyle(XMLReader $xmlReader, \DOMElement $domNode) { - $ret = null; - $mapping = array( - 'w:type' => 'breakType', 'w:pgSz' => 'pageSize', - 'w:pgMar' => 'pageMargin', 'w:cols' => 'columns', - 'w:headerReference' => 'header', 'w:footerReference' => 'footer', + $styleDefs = array( + 'breakType' => array(self::READ_VALUE, 'w:type'), + 'pageSizeW' => array(self::READ_VALUE, 'w:pgSz', 'w:w'), + 'pageSizeH' => array(self::READ_VALUE, 'w:pgSz', 'w:h'), + 'orientation' => array(self::READ_VALUE, 'w:pgSz', 'w:orient'), + 'colsNum' => array(self::READ_VALUE, 'w:cols', 'w:num'), + 'colsSpace' => array(self::READ_VALUE, 'w:cols', 'w:space'), + 'topMargin' => array(self::READ_VALUE, 'w:pgMar', 'w:top'), + 'leftMargin' => array(self::READ_VALUE, 'w:pgMar', 'w:left'), + 'bottomMargin' => array(self::READ_VALUE, 'w:pgMar', 'w:bottom'), + 'rightMargin' => array(self::READ_VALUE, 'w:pgMar', 'w:right'), + 'headerHeight' => array(self::READ_VALUE, 'w:pgMar', 'w:header'), + 'footerHeight' => array(self::READ_VALUE, 'w:pgMar', 'w:footer'), + 'gutter' => array(self::READ_VALUE, 'w:pgMar', 'w:gutter'), ); + $styles = $this->readStyleDefs($xmlReader, $domNode, $styleDefs); + + // Header and footer + // @todo Cleanup this part $nodes = $xmlReader->getElements('*', $domNode); foreach ($nodes as $node) { - if (!array_key_exists($node->nodeName, $mapping)) { - continue; - } - $property = $mapping[$node->nodeName]; - switch ($node->nodeName) { - - case 'w:type': - $ret['breakType'] = $xmlReader->getAttribute('w:val', $node); - break; - - case 'w:pgSz': - $ret['pageSizeW'] = $xmlReader->getAttribute('w:w', $node); - $ret['pageSizeH'] = $xmlReader->getAttribute('w:h', $node); - $ret['orientation'] = $xmlReader->getAttribute('w:orient', $node); - break; - - case 'w:pgMar': - $ret['topMargin'] = $xmlReader->getAttribute('w:top', $node); - $ret['leftMargin'] = $xmlReader->getAttribute('w:left', $node); - $ret['bottomMargin'] = $xmlReader->getAttribute('w:bottom', $node); - $ret['rightMargin'] = $xmlReader->getAttribute('w:right', $node); - $ret['headerHeight'] = $xmlReader->getAttribute('w:header', $node); - $ret['footerHeight'] = $xmlReader->getAttribute('w:footer', $node); - $ret['gutter'] = $xmlReader->getAttribute('w:gutter', $node); - break; - - case 'w:cols': - $ret['colsNum'] = $xmlReader->getAttribute('w:num', $node); - $ret['colsSpace'] = $xmlReader->getAttribute('w:space', $node); - break; - - case 'w:headerReference': - case 'w:footerReference': - $id = $xmlReader->getAttribute('r:id', $node); - $ret['hf'][$id] = array( - 'method' => $property, - 'type' => $xmlReader->getAttribute('w:type', $node), - ); - break; + if ($node->nodeName == 'w:headerReference' || $node->nodeName == 'w:footerReference') { + $id = $xmlReader->getAttribute('r:id', $node); + $styles['hf'][$id] = array( + 'method' => str_replace('w:', '', str_replace('Reference', '', $node->nodeName)), + 'type' => $xmlReader->getAttribute('w:type', $node), + ); } } - return $ret; - } - - /** - * Read w:tcPr - * - * @return array|null - */ - private function readCellStyle(XMLReader $xmlReader, \DOMElement $domNode) - { - $style = null; - $mapping = array( - 'w:shd' => 'bgColor', - 'w:vAlign' => 'valign', 'w:textDirection' => 'textDirection', - 'w:gridSpan' => 'gridSpan', 'w:vMerge' => 'vMerge', - ); - $nodes = $xmlReader->getElements('*', $domNode); - foreach ($nodes as $node) { - if (!array_key_exists($node->nodeName, $mapping)) { - continue; - } - $property = $mapping[$node->nodeName]; - switch ($node->nodeName) { - case 'w:shd': - $style['bgColor'] = $xmlReader->getAttribute('w:fill', $node); - break; - - default: - $style[$property] = $xmlReader->getAttribute('w:val', $node); - break; - } - } - - return $style; + return $styles; } } diff --git a/src/PhpWord/Reader/Word2007/Numbering.php b/src/PhpWord/Reader/Word2007/Numbering.php index 68a36d57..81939ae8 100644 --- a/src/PhpWord/Reader/Word2007/Numbering.php +++ b/src/PhpWord/Reader/Word2007/Numbering.php @@ -87,6 +87,8 @@ class Numbering extends AbstractPart /** * Read numbering level definition from w:abstractNum and w:num * + * @param \PhpOffice\PhpWord\Shared\XMLReader $xmlReader + * @param \DOMElement $subnode * @param integer $levelId * @return array */ diff --git a/src/PhpWord/Settings.php b/src/PhpWord/Settings.php index b8dfe8cd..8d9e2ace 100644 --- a/src/PhpWord/Settings.php +++ b/src/PhpWord/Settings.php @@ -29,8 +29,9 @@ class Settings * * @const string */ - const PCLZIP = 'PhpOffice\\PhpWord\\Shared\\ZipArchive'; const ZIPARCHIVE = 'ZipArchive'; + const PCLZIP = 'PclZip'; + const OLD_LIB = 'PhpOffice\\PhpWord\\Shared\\ZipArchive'; // @deprecated 0.11 /** * PDF rendering libraries @@ -38,6 +39,8 @@ class Settings * @const string */ const PDF_RENDERER_DOMPDF = 'DomPDF'; + const PDF_RENDERER_TCPDF = 'TCPDF'; + const PDF_RENDERER_MPDF = 'MPDF'; /** * Measurement units multiplication factor @@ -48,14 +51,25 @@ class Settings * - Indentation: left, right, firstLine, hanging * - Spacing: before, after * - * @const int|float + * @const string */ - const UNIT_TWIP = 1; // = 1/20 point - const UNIT_CM = 567; - const UNIT_MM = 56.7; - const UNIT_INCH = 1440; - const UNIT_POINT = 20; // = 1/72 inch - const UNIT_PICA = 240; // = 1/6 inch = 12 points + const UNIT_TWIP = 'twip'; // = 1/20 point + const UNIT_CM = 'cm'; + const UNIT_MM = 'mm'; + const UNIT_INCH = 'inch'; + const UNIT_POINT = 'point'; // = 1/72 inch + const UNIT_PICA = 'pica'; // = 1/6 inch = 12 points + + /** + * Default font settings + * + * OOXML defined font size values in halfpoints, i.e. twice of what PhpWord + * use, and the conversion will be conducted during XML writing. + */ + const DEFAULT_FONT_NAME = 'Arial'; + const DEFAULT_FONT_SIZE = 10; + const DEFAULT_FONT_COLOR = '000000'; + const DEFAULT_FONT_CONTENT_TYPE = 'default'; // default|eastAsia|cs /** * Compatibility option for XMLWriter @@ -71,13 +85,6 @@ class Settings */ private static $zipClass = self::ZIPARCHIVE; - /** - * Name of the classes used for PDF renderer - * - * @var array - */ - private static $pdfRenderers = array(self::PDF_RENDERER_DOMPDF); - /** * Name of the external Library used for rendering PDF files * @@ -95,10 +102,23 @@ class Settings /** * Measurement unit * - * @var string + * @var int|float */ private static $measurementUnit = self::UNIT_TWIP; + /** + * Default font name + * + * @var string + */ + private static $defaultFontName = self::DEFAULT_FONT_NAME; + + /** + * Default font size + * @var int + */ + private static $defaultFontSize = self::DEFAULT_FONT_SIZE; + /** * Return the compatibility option used by the XMLWriter * @@ -119,12 +139,10 @@ class Settings */ public static function setCompatibility($compatibility) { - if (is_bool($compatibility)) { - self::$xmlWriterCompatibility = $compatibility; - return true; - } + $compatibility = (bool)$compatibility; + self::$xmlWriterCompatibility = $compatibility; - return false; + return true; } /** @@ -145,8 +163,7 @@ class Settings */ public static function setZipClass($zipClass) { - if (($zipClass === self::PCLZIP) || - ($zipClass === self::ZIPARCHIVE)) { + if (in_array($zipClass, array(self::PCLZIP, self::ZIPARCHIVE, self::OLD_LIB))) { self::$zipClass = $zipClass; return true; } @@ -186,7 +203,8 @@ class Settings */ public static function setPdfRendererName($libraryName) { - if (!in_array($libraryName, self::$pdfRenderers)) { + $pdfRenderers = array(self::PDF_RENDERER_DOMPDF, self::PDF_RENDERER_TCPDF, self::PDF_RENDERER_MPDF); + if (!in_array($libraryName, $pdfRenderers)) { return false; } self::$pdfRendererName = $libraryName; @@ -222,7 +240,7 @@ class Settings /** * Get measurement unit * - * @return int|float + * @return string */ public static function getMeasurementUnit() { @@ -232,7 +250,7 @@ class Settings /** * Set measurement unit * - * @param int|float $value + * @param string $value * @return bool */ public static function setMeasurementUnit($value) @@ -247,6 +265,102 @@ class Settings return true; } + /** + * Get default font name + * + * @return string + */ + public static function getDefaultFontName() + { + return self::$defaultFontName; + } + + /** + * Set default font name + * + * @param string $value + * @return bool + */ + public static function setDefaultFontName($value) + { + if (is_string($value) && trim($value) !== '') { + self::$defaultFontName = $value; + return true; + } + + return false; + } + + /** + * Get default font size + * + * @return integer + */ + public static function getDefaultFontSize() + { + return self::$defaultFontSize; + } + + /** + * Set default font size + * + * @param int $value + * @return bool + */ + public static function setDefaultFontSize($value) + { + $value = intval($value); + if ($value > 0) { + self::$defaultFontSize = $value; + return true; + } + + return false; + } + + /** + * Load setting from phpword.yml or phpword.yml.dist + * + * @param string $filename + * @return array + */ + public static function loadConfig($filename = null) + { + // Get config file + $configFile = null; + $configPath = __DIR__ . '/../../'; + if ($filename !== null) { + $files = array($filename); + } else { + $files = array("{$configPath}phpword.ini", "{$configPath}phpword.ini.dist"); + } + foreach ($files as $file) { + if (file_exists($file)) { + $configFile = realpath($file); + break; + } + } + + // Parse config file + $config = array(); + if ($configFile !== null) { + $config = parse_ini_file($configFile); + if ($config === false) { + return $config; + } + } + + // Set config value + foreach ($config as $key => $value) { + $method = "set{$key}"; + if (method_exists(__CLASS__, $method)) { + self::$method($value); + } + } + + return $config; + } + /** * Return the compatibility option used by the XMLWriter * diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php index 1df56e68..501d2404 100644 --- a/src/PhpWord/Shared/Html.php +++ b/src/PhpWord/Shared/Html.php @@ -27,9 +27,8 @@ class Html * * Note: $stylesheet parameter is removed to avoid PHPMD error for unused parameter * - * @param \PhpOffice\PhpWord\Element\AbstractElement $object Where the parts need to be added + * @param \PhpOffice\PhpWord\Element\AbstractContainer $object Where the parts need to be added * @param string $html the code to parse - * */ public static function addHtml($object, $html) { @@ -53,7 +52,7 @@ class Html * * @param \DOMNode $node Node to check on attributes and to compile a style array * @param array $style is supplied, the inline style attributes are added to the already existing style - * + * @return array */ protected static function parseInlineStyle($node, $style = array()) { @@ -93,6 +92,7 @@ class Html } } } + return $style; } @@ -100,10 +100,9 @@ class Html * parse a node and add a corresponding element to the object * * @param \DOMNode $node node to parse - * @param \PhpOffice\PhpWord\Element\AbstractElement $object object to add an element corresponding with the node + * @param \PhpOffice\PhpWord\Element\AbstractContainer $object object to add an element corresponding with the node * @param array $styles Array with all styles * @param array $data Array to transport data to a next level in the DOM tree, for example level of listitems - * */ protected static function parseNode( $node, @@ -171,17 +170,26 @@ class Html case 'table': $styles['paragraphStyle'] = self::parseInlineStyle($node, $styles['paragraphStyle']); $newobject = $object->addTable(); - // if ($attributes->getNamedItem('width') !== null)$newobject->setWidth($attributes->getNamedItem('width')->value); + // if ($attributes->getNamedItem('width') !== null) { + // $newobject->setWidth($attributes->getNamedItem('width')->value); + // } break; case 'tr': + /** @var \PhpOffice\PhpWord\Element\Table $object Type hint */ $styles['paragraphStyle'] = self::parseInlineStyle($node, $styles['paragraphStyle']); $newobject = $object->addRow(); - // if ($attributes->getNamedItem('height') !== null)$newobject->setHeight($attributes->getNamedItem('height')->value); + // if ($attributes->getNamedItem('height') !== null) { + // $newobject->setHeight($attributes->getNamedItem('height')->value); + // } break; case 'td': + /** @var \PhpOffice\PhpWord\Element\Row $object Type hint */ $styles['paragraphStyle'] = self::parseInlineStyle($node, $styles['paragraphStyle']); - // if ($attributes->getNamedItem('width') !== null)$newobject=$object->addCell($width=$attributes->getNamedItem('width')->value); - // else $newobject=$object->addCell(); + // if ($attributes->getNamedItem('width') !== null) { + // $newobject=$object->addCell($width=$attributes->getNamedItem('width')->value); + // } else { + // $newobject=$object->addCell(); + // } $newobject = $object->addCell(); break; case 'ul': @@ -207,12 +215,19 @@ class Html case 'li': $cNodes = $node->childNodes; if (count($cNodes) > 0) { + $text = ''; foreach ($cNodes as $cNode) { if ($cNode->nodeName == '#text') { $text = $cNode->nodeValue; } } - $object->addListItem($text, $data['listdepth'], $styles['fontStyle'], $styles['listStyle'], $styles['paragraphStyle']); + $object->addListItem( + $text, + $data['listdepth'], + $styles['fontStyle'], + $styles['listStyle'], + $styles['paragraphStyle'] + ); } } diff --git a/src/PhpWord/Shared/String.php b/src/PhpWord/Shared/String.php index 6ebcc65d..259e904c 100644 --- a/src/PhpWord/Shared/String.php +++ b/src/PhpWord/Shared/String.php @@ -85,6 +85,54 @@ class String return $value; } + /** + * Returns unicode from UTF8 text + * + * @param string $text UTF8 text + * @return string Unicode text + * @since 0.11.0 + * @link http://www.randomchaos.com/documents/?source=php_and_unicode + */ + public static function toUnicode($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; + } + } + } + + // Converts text with utf8 characters into rtf utf8 entites preserving ascii + $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 * diff --git a/src/PhpWord/Shared/XMLReader.php b/src/PhpWord/Shared/XMLReader.php index 415526ee..60474ce9 100644 --- a/src/PhpWord/Shared/XMLReader.php +++ b/src/PhpWord/Shared/XMLReader.php @@ -18,7 +18,6 @@ namespace PhpOffice\PhpWord\Shared; use PhpOffice\PhpWord\Exception\Exception; -use PhpOffice\PhpWord\Settings; /** * XML Reader wrapper @@ -47,6 +46,7 @@ class XMLReader * @param string $zipFile * @param string $xmlFile * @return \DOMDocument|false + * @throws \PhpOffice\PhpWord\Exception\Exception */ public function getDomFromZip($zipFile, $xmlFile) { @@ -54,12 +54,8 @@ class XMLReader throw new Exception('Cannot find archive file.'); } - $zipClass = Settings::getZipClass(); - $zip = new $zipClass(); - $canOpen = $zip->open($zipFile); - if ($canOpen === false) { - throw new Exception('Cannot open archive file.'); - } + $zip = new ZipArchive(); + $zip->open($zipFile); $contents = $zip->getFromName($xmlFile); $zip->close(); @@ -76,6 +72,7 @@ class XMLReader * Get elements * * @param string $path + * @param \DOMElement $contextNode * @return \DOMNodeList */ public function getElements($path, \DOMElement $contextNode = null) @@ -94,9 +91,10 @@ class XMLReader * Get element * * @param string $path + * @param \DOMElement $contextNode * @return \DOMElement|null */ - public function getElement($path, \DOMElement $contextNode) + public function getElement($path, \DOMElement $contextNode = null) { $elements = $this->getElements($path, $contextNode); if ($elements->length > 0) { @@ -110,19 +108,23 @@ class XMLReader * Get element attribute * * @param string $attribute + * @param \DOMElement $contextNode * @param string $path * @return string|null */ - public function getAttribute($attribute, \DOMElement $contextNode, $path = null) + public function getAttribute($attribute, \DOMElement $contextNode = null, $path = null) { - if (is_null($path)) { - $return = $contextNode->getAttribute($attribute); - } else { + $return = null; + if ($path !== null) { $elements = $this->getElements($path, $contextNode); if ($elements->length > 0) { - $return = $elements->item(0)->getAttribute($attribute); - } else { - $return = null; + /** @var \DOMElement $node Type hint */ + $node = $elements->item(0); + $return = $node->getAttribute($attribute); + } + } else { + if ($contextNode !== null) { + $return = $contextNode->getAttribute($attribute); } } @@ -133,9 +135,10 @@ class XMLReader * Get element value * * @param string $path + * @param \DOMElement $contextNode * @return string|null */ - public function getValue($path, \DOMElement $contextNode) + public function getValue($path, \DOMElement $contextNode = null) { $elements = $this->getElements($path, $contextNode); if ($elements->length > 0) { @@ -149,9 +152,10 @@ class XMLReader * Count elements * * @param string $path + * @param \DOMElement $contextNode * @return integer */ - public function countElements($path, \DOMElement $contextNode) + public function countElements($path, \DOMElement $contextNode = null) { $elements = $this->getElements($path, $contextNode); @@ -162,9 +166,10 @@ class XMLReader * Element exists * * @param string $path + * @param \DOMElement $contextNode * @return boolean */ - public function elementExists($path, \DOMElement $contextNode) + public function elementExists($path, \DOMElement $contextNode = null) { return $this->getElements($path, $contextNode)->length > 0; } diff --git a/src/PhpWord/Shared/XMLWriter.php b/src/PhpWord/Shared/XMLWriter.php index a16fe0b4..683e09c0 100644 --- a/src/PhpWord/Shared/XMLWriter.php +++ b/src/PhpWord/Shared/XMLWriter.php @@ -19,21 +19,16 @@ namespace PhpOffice\PhpWord\Shared; use PhpOffice\PhpWord\Settings; -// @codeCoverageIgnoreStart -if (!defined('DATE_W3C')) { - define('DATE_W3C', 'Y-m-d\TH:i:sP'); -} -// @codeCoverageIgnoreEnd - /** * XMLWriter wrapper * - * @method bool writeElement(string $name, string $content = null) - * @method bool startElement(string $name) - * @method bool writeAttribute(string $name, string $value) * @method bool endElement() * @method bool startDocument(string $version = 1.0, string $encoding = null, string $standalone = null) + * @method bool startElement(string $name) * @method bool text(string $content) + * @method bool writeAttribute(string $name, mixed $value) + * @method bool writeElement(string $name, string $content = null) + * @method bool writeRaw(string $content) */ class XMLWriter { @@ -63,6 +58,11 @@ class XMLWriter */ public function __construct($tempLocation = self::STORAGE_MEMORY, $tempFolder = './') { + // Define date format + if (!defined('DATE_W3C')) { + define('DATE_W3C', 'Y-m-d\TH:i:sP'); + } + // Create internal XMLWriter $this->xmlWriter = new \XMLWriter(); @@ -135,32 +135,17 @@ class XMLWriter } } - /** - * Fallback method for writeRaw, introduced in PHP 5.2 - * - * @param string $text - * @return bool - */ - public function writeRaw($text) - { - if (isset($this->xmlWriter) && is_object($this->xmlWriter) && (method_exists($this->xmlWriter, 'writeRaw'))) { - return $this->xmlWriter->writeRaw($text); - } - - return $this->text($text); - } - /** * Write element if ... * * @param bool $condition * @param string $element * @param string $attribute - * @param string $value + * @param mixed $value */ public function writeElementIf($condition, $element, $attribute = null, $value = null) { - if ($condition) { + if ($condition == true) { if (is_null($attribute)) { $this->xmlWriter->writeElement($element, $value); } else { @@ -176,11 +161,11 @@ class XMLWriter * * @param bool $condition * @param string $attribute - * @param string $value + * @param mixed $value */ public function writeAttributeIf($condition, $attribute, $value) { - if ($condition) { + if ($condition == true) { $this->xmlWriter->writeAttribute($attribute, $value); } } diff --git a/src/PhpWord/Shared/ZipArchive.php b/src/PhpWord/Shared/ZipArchive.php index 8c9f10b8..a5a37ec0 100644 --- a/src/PhpWord/Shared/ZipArchive.php +++ b/src/PhpWord/Shared/ZipArchive.php @@ -17,32 +17,43 @@ namespace PhpOffice\PhpWord\Shared; -// PCLZIP needs the temp path to end in a back slash -// @codeCoverageIgnoreStart -if (!defined('PCLZIP_TEMPORARY_DIR')) { - define('PCLZIP_TEMPORARY_DIR', sys_get_temp_dir() . '/'); -} -require_once 'PCLZip/pclzip.lib.php'; -// @codeCoverageIgnoreEnd +use PhpOffice\PhpWord\Exception\Exception; +use PhpOffice\PhpWord\Settings; /** - * PCLZip wrapper + * ZipArchive wrapper + * + * Wraps zip archive functionality of PHP ZipArchive and PCLZip. PHP ZipArchive + * properties and methods are bypassed and used as the model for the PCLZip + * emulation. Only needed PHP ZipArchive features are implemented. + * + * @method bool addFile(string $filename, string $localname = null) + * @method bool addFromString(string $localname, string $contents) + * @method string getNameIndex(int $index) + * @method int locateName(string $name) * * @since 0.10.0 */ class ZipArchive { - /** constants */ - const OVERWRITE = 'OVERWRITE'; - const CREATE = 'CREATE'; + /** @const int Flags for open method */ + const CREATE = 1; // Emulate \ZipArchive::CREATE + const OVERWRITE = 8; // Emulate \ZipArchive::OVERWRITE /** * Number of files (emulate ZipArchive::$numFiles) * - * @var string + * @var int */ public $numFiles = 0; + /** + * Archive filename (emulate ZipArchive::$filename) + * + * @var string + */ + public $filename; + /** * Temporary storage directory * @@ -51,44 +62,161 @@ class ZipArchive private $tempDir; /** - * Zip Archive Stream Handle + * Internal zip archive object * - * @var string + * @var \ZipArchive|\PclZip */ private $zip; + /** + * Use PCLZip (default behaviour) + * + * @var bool + */ + private $usePclzip = true; + + /** + * Create new instance + */ + public function __construct() + { + $this->usePclzip = (Settings::getZipClass() != 'ZipArchive'); + if ($this->usePclzip) { + if (!defined('PCLZIP_TEMPORARY_DIR')) { + define('PCLZIP_TEMPORARY_DIR', sys_get_temp_dir() . '/'); + } + require_once 'PCLZip/pclzip.lib.php'; + } + } + + /** + * Catch function calls: pass to ZipArchive or PCLZip + * + * `call_user_func_array` can only used for public function, hence the `public` in all `pcl...` methods + * + * @param mixed $function + * @param mixed $args + * @return mixed + */ + public function __call($function, $args) + { + // Set object and function + $zipFunction = $function; + if (!$this->usePclzip) { + $zipObject = $this->zip; + } else { + $zipObject = $this; + $zipFunction = "pclzip{$zipFunction}"; + } + + // Run function + $result = false; + if (method_exists($zipObject, $zipFunction)) { + $result = @call_user_func_array(array($zipObject, $zipFunction), $args); + } + + return $result; + } + /** * Open a new zip archive * - * @param string $filename Filename for the zip archive - * @return boolean + * @param string $filename The file name of the ZIP archive to open + * @param int $flags The mode to use to open the archive + * @return bool */ - public function open($filename) + public function open($filename, $flags = null) { - $this->tempDir = sys_get_temp_dir(); - $this->zip = new \PclZip($filename); - $this->numFiles = count($this->zip->listContent()); + $result = true; + $this->filename = $filename; + + if (!$this->usePclzip) { + $zip = new \ZipArchive(); + $result = $zip->open($this->filename, $flags); + + // Scrutizer will report the property numFiles does not exist + // See https://github.com/scrutinizer-ci/php-analyzer/issues/190 + $this->numFiles = $zip->numFiles; + } else { + $zip = new \PclZip($this->filename); + $this->tempDir = sys_get_temp_dir(); + $this->numFiles = count($zip->listContent()); + } + $this->zip = $zip; + + return $result; + } + + /** + * Close the active archive + * + * @return bool + * @throws \PhpOffice\PhpWord\Exception\Exception + */ + public function close() + { + if (!$this->usePclzip) { + if ($this->zip->close() === false) { + throw new Exception("Could not close zip file $this->filename."); + } + } return true; } /** - * Close this zip archive (emulate \ZipArchive) + * Extract the archive contents (emulate \ZipArchive) * - * @codeCoverageIgnore + * @param string $destination + * @param string|array $entries + * @return bool + * @since 0.10.0 */ - public function close() + public function extractTo($destination, $entries = null) { + if (!is_dir($destination)) { + return false; + } + + if (!$this->usePclzip) { + return $this->zip->extractTo($destination, $entries); + } else { + return $this->pclzipExtractTo($destination, $entries); + } + } + + /** + * Extract file from archive by given file name (emulate \ZipArchive) + * + * @param string $filename Filename for the file in zip archive + * @return string $contents File string contents + */ + public function getFromName($filename) + { + if (!$this->usePclzip) { + $contents = $this->zip->getFromName($filename); + if ($contents === false) { + $filename = substr($filename, 1); + $contents = $this->zip->getFromName($filename); + } + } else { + $contents = $this->pclzipGetFromName($filename); + } + + return $contents; } /** * Add a new file to the zip archive (emulate \ZipArchive) * - * @param string $filename Directory/Name of the file to add to the zip archive + * @param string $filename Directory/Name of the file to add to the zip archive * @param string $localname Directory/Name of the file added to the zip + * @return bool */ - public function addFile($filename, $localname = null) + public function pclzipAddFile($filename, $localname = null) { + /** @var \PclZip $zip Type hint */ + $zip = $this->zip; $filename = realpath($filename); $filenameParts = pathinfo($filename); $localnameParts = pathinfo($localname); @@ -102,13 +230,10 @@ class ZipArchive $filenameParts = pathinfo($temppath); } - $res = $this->zip->add( - $filename, - PCLZIP_OPT_REMOVE_PATH, - $filenameParts['dirname'], - PCLZIP_OPT_ADD_PATH, - $localnameParts["dirname"] - ); + $pathRemoved = $filenameParts['dirname']; + $pathAdded = $localnameParts['dirname']; + + $res = $zip->add($filename, PCLZIP_OPT_REMOVE_PATH, $pathRemoved, PCLZIP_OPT_ADD_PATH, $pathAdded); return ($res == 0) ? false : true; } @@ -117,10 +242,13 @@ class ZipArchive * Add a new file to the zip archive from a string of raw data (emulate \ZipArchive) * * @param string $localname Directory/Name of the file to add to the zip archive - * @param string $contents String of data to add to the zip archive + * @param string $contents String of data to add to the zip archive + * @return bool */ - public function addFromString($localname, $contents) + public function pclzipAddFromString($localname, $contents) { + /** @var \PclZip $zip Type hint */ + $zip = $this->zip; $filenameParts = pathinfo($localname); // Write $contents to a temp file @@ -129,13 +257,11 @@ class ZipArchive fclose($handle); // Add temp file to zip - $res = $this->zip->add( - $this->tempDir . '/' . $filenameParts["basename"], - PCLZIP_OPT_REMOVE_PATH, - $this->tempDir, - PCLZIP_OPT_ADD_PATH, - $filenameParts["dirname"] - ); + $filename = $this->tempDir . '/' . $filenameParts["basename"]; + $pathRemoved = $this->tempDir; + $pathAdded = $filenameParts['dirname']; + + $res = $zip->add($filename, PCLZIP_OPT_REMOVE_PATH, $pathRemoved, PCLZIP_OPT_ADD_PATH, $pathAdded); // Remove temp file @unlink($this->tempDir . '/' . $filenameParts["basename"]); @@ -143,15 +269,97 @@ class ZipArchive return ($res == 0) ? false : true; } + /** + * Extract the archive contents (emulate \ZipArchive) + * + * @param string $destination + * @param string|array $entries + * @return bool + * @since 0.10.0 + */ + public function pclzipExtractTo($destination, $entries = null) + { + /** @var \PclZip $zip Type hint */ + $zip = $this->zip; + + // Extract all files + if (is_null($entries)) { + $result = $zip->extract(PCLZIP_OPT_PATH, $destination); + return ($result > 0) ? true : false; + } + + // Extract by entries + if (!is_array($entries)) { + $entries = array($entries); + } + foreach ($entries as $entry) { + $entryIndex = $this->locateName($entry); + $result = $zip->extractByIndex($entryIndex, PCLZIP_OPT_PATH, $destination); + if ($result <= 0) { + return false; + } + } + + return true; + } + + /** + * Extract file from archive by given file name (emulate \ZipArchive) + * + * @param string $filename Filename for the file in zip archive + * @return string $contents File string contents + */ + public function pclzipGetFromName($filename) + { + /** @var \PclZip $zip Type hint */ + $zip = $this->zip; + $listIndex = $this->pclzipLocateName($filename); + $contents = false; + + if ($listIndex !== false) { + $extracted = $zip->extractByIndex($listIndex, PCLZIP_OPT_EXTRACT_AS_STRING); + } else { + $filename = substr($filename, 1); + $listIndex = $this->pclzipLocateName($filename); + $extracted = $zip->extractByIndex($listIndex, PCLZIP_OPT_EXTRACT_AS_STRING); + } + if ((is_array($extracted)) && ($extracted != 0)) { + $contents = $extracted[0]["content"]; + } + + return $contents; + } + + /** + * Returns the name of an entry using its index (emulate \ZipArchive) + * + * @param int $index + * @return string + * @since 0.10.0 + */ + public function pclzipGetNameIndex($index) + { + /** @var \PclZip $zip Type hint */ + $zip = $this->zip; + $list = $zip->listContent(); + if (isset($list[$index])) { + return $list[$index]['filename']; + } else { + return false; + } + } + /** * Returns the index of the entry in the archive (emulate \ZipArchive) * * @param string $filename Filename for the file in zip archive - * @return integer|false + * @return int */ - public function locateName($filename) + public function pclzipLocateName($filename) { - $list = $this->zip->listContent(); + /** @var \PclZip $zip Type hint */ + $zip = $this->zip; + $list = $zip->listContent(); $listCount = count($list); $listIndex = -1; for ($i = 0; $i < $listCount; ++$i) { @@ -164,81 +372,4 @@ class ZipArchive return ($listIndex > -1) ? $listIndex : false; } - - /** - * Extract file from archive by given file name (emulate \ZipArchive) - * - * @param string $filename Filename for the file in zip archive - * @return string|false $contents File string contents - */ - public function getFromName($filename) - { - $listIndex = $this->locateName($filename); - $contents = false; - - if ($listIndex !== false) { - $extracted = $this->zip->extractByIndex($listIndex, PCLZIP_OPT_EXTRACT_AS_STRING); - } else { - $filename = substr($filename, 1); - $listIndex = $this->locateName($filename); - $extracted = $this->zip->extractByIndex($listIndex, PCLZIP_OPT_EXTRACT_AS_STRING); - } - if ((is_array($extracted)) && ($extracted != 0)) { - $contents = $extracted[0]["content"]; - } - - return $contents; - } - - /** - * Returns the name of an entry using its index (emulate \ZipArchive) - * - * @param integer $index - * @return string|false - * @since 0.10.0 - */ - public function getNameIndex($index) - { - $list = $this->zip->listContent(); - if (isset($list[$index])) { - return $list[$index]['filename']; - } else { - return false; - } - } - - /** - * Extract the archive contents (emulate \ZipArchive) - * - * @param string $destination - * @param string|array $entries - * @return boolean - * @since 0.10.0 - */ - public function extractTo($destination, $entries = null) - { - if (!is_dir($destination)) { - return false; - } - - // Extract all files - if (is_null($entries)) { - $result = $this->zip->extract(PCLZIP_OPT_PATH, $destination); - return ($result > 0) ? true : false; - } - - // Extract by entries - if (!is_array($entries)) { - $entries = array($entries); - } - foreach ($entries as $entry) { - $entryIndex = $this->locateName($entry); - $result = $this->zip->extractByIndex($entryIndex, PCLZIP_OPT_PATH, $destination); - if ($result <= 0) { - return false; - } - } - - return true; - } } diff --git a/src/PhpWord/Style.php b/src/PhpWord/Style.php index 25e5785b..d56c73fe 100644 --- a/src/PhpWord/Style.php +++ b/src/PhpWord/Style.php @@ -17,6 +17,7 @@ namespace PhpOffice\PhpWord; +use PhpOffice\PhpWord\Style\AbstractStyle; use PhpOffice\PhpWord\Style\Font; use PhpOffice\PhpWord\Style\Numbering; use PhpOffice\PhpWord\Style\Paragraph; @@ -39,10 +40,11 @@ class Style * * @param string $styleName * @param array $styles + * @return \PhpOffice\PhpWord\Style\Paragraph */ public static function addParagraphStyle($styleName, $styles) { - self::setStyleValues($styleName, new Paragraph(), $styles); + return self::setStyleValues($styleName, new Paragraph(), $styles); } /** @@ -51,10 +53,11 @@ class Style * @param string $styleName * @param array $fontStyle * @param array $paragraphStyle + * @return \PhpOffice\PhpWord\Style\Font */ public static function addFontStyle($styleName, $fontStyle, $paragraphStyle = null) { - self::setStyleValues($styleName, new Font('text', $paragraphStyle), $fontStyle); + return self::setStyleValues($styleName, new Font('text', $paragraphStyle), $fontStyle); } /** @@ -62,10 +65,37 @@ class Style * * @param string $styleName * @param array $styles + * @return \PhpOffice\PhpWord\Style\Font */ public static function addLinkStyle($styleName, $styles) { - self::setStyleValues($styleName, new Font('link'), $styles); + return self::setStyleValues($styleName, new Font('link'), $styles); + } + + /** + * Add numbering style + * + * @param string $styleName + * @param array $styleValues + * @return \PhpOffice\PhpWord\Style\Numbering + * @since 0.10.0 + */ + public static function addNumberingStyle($styleName, $styleValues) + { + return self::setStyleValues($styleName, new Numbering(), $styleValues); + } + + /** + * Add title style + * + * @param int $depth + * @param array $fontStyle + * @param array $paragraphStyle + * @return \PhpOffice\PhpWord\Style\Font + */ + public static function addTitleStyle($depth, $fontStyle, $paragraphStyle = null) + { + return self::setStyleValues("Heading_{$depth}", new Font('title', $paragraphStyle), $fontStyle); } /** @@ -74,41 +104,17 @@ class Style * @param string $styleName * @param array $styleTable * @param array|null $styleFirstRow + * @return \PhpOffice\PhpWord\Style\Table */ public static function addTableStyle($styleName, $styleTable, $styleFirstRow = null) { - self::setStyleValues($styleName, new Table($styleTable, $styleFirstRow), null); - } - - /** - * Add title style - * - * @param int $titleCount - * @param array $fontStyle - * @param array $paragraphStyle - */ - public static function addTitleStyle($titleCount, $fontStyle, $paragraphStyle = null) - { - self::setStyleValues("Heading_{$titleCount}", new Font('title', $paragraphStyle), $fontStyle); - } - - /** - * Add numbering style - * - * @param string $styleName - * @param array $styleValues - * @return Numbering - * @since 0.10.0 - */ - public static function addNumberingStyle($styleName, $styleValues) - { - self::setStyleValues($styleName, new Numbering(), $styleValues); + return self::setStyleValues($styleName, new Table($styleTable, $styleFirstRow), null); } /** * Count styles * - * @return integer + * @return int * @since 0.10.0 */ public static function countStyles() @@ -129,16 +135,17 @@ class Style * Set default paragraph style * * @param array $styles Paragraph style definition + * @return \PhpOffice\PhpWord\Style\Paragraph */ public static function setDefaultParagraphStyle($styles) { - self::addParagraphStyle('Normal', $styles); + return self::addParagraphStyle('Normal', $styles); } /** * Get all styles * - * @return array + * @return \PhpOffice\PhpWord\Style\AbstractStyle[] */ public static function getStyles() { @@ -149,7 +156,7 @@ class Style * Get style by name * * @param string $styleName - * @return Paragraph|Font|Table|Numbering|null + * @return \PhpOffice\PhpWord\Style\AbstractStyle Paragraph|Font|Table|Numbering */ public static function getStyle($styleName) { @@ -163,21 +170,30 @@ class Style /** * Set style values and put it to static style collection * - * @param string $styleName - * @param Paragraph|Font|Table|Numbering $styleObject - * @param array|null $styleValues + * The $styleValues could be an array or object + * + * @param string $name + * @param \PhpOffice\PhpWord\Style\AbstractStyle $style + * @param array|\PhpOffice\PhpWord\Style\AbstractStyle $value + * @return \PhpOffice\PhpWord\Style\AbstractStyle */ - private static function setStyleValues($styleName, $styleObject, $styleValues = null) + private static function setStyleValues($name, $style, $value = null) { - if (!array_key_exists($styleName, self::$styles)) { - if (!is_null($styleValues) && is_array($styleValues)) { - foreach ($styleValues as $key => $value) { - $styleObject->setStyleValue($key, $value); + if (!array_key_exists($name, self::$styles)) { + if ($value !== null) { + if (is_array($value)) { + $style->setStyleByArray($value); + } elseif ($value instanceof AbstractStyle) { + if (get_class($style) == get_class($value)) { + $style = $value; + } } } - $styleObject->setStyleName($styleName); - $styleObject->setIndex(self::countStyles() + 1); // One based index - self::$styles[$styleName] = $styleObject; + $style->setStyleName($name); + $style->setIndex(self::countStyles() + 1); // One based index + self::$styles[$name] = $style; } + + return self::getStyle($name); } } diff --git a/src/PhpWord/Style/AbstractStyle.php b/src/PhpWord/Style/AbstractStyle.php index d909a20a..1b916934 100644 --- a/src/PhpWord/Style/AbstractStyle.php +++ b/src/PhpWord/Style/AbstractStyle.php @@ -49,6 +49,14 @@ abstract class AbstractStyle */ protected $aliases = array(); + /** + * Is this an automatic style? (Used primarily in OpenDocument driver) + * + * @var bool + * @since 0.11.0 + */ + private $isAuto = false; + /** * Get style name * @@ -95,6 +103,29 @@ abstract class AbstractStyle return $this; } + /** + * Get is automatic style flag + * + * @return bool + */ + public function isAuto() + { + return $this->isAuto; + } + + /** + * Set is automatic style flag + * + * @param bool $value + * @return self + */ + public function setAuto($value = true) + { + $this->isAuto = $this->setBoolVal($value, $this->isAuto); + + return $this; + } + /** * Set style value template method * @@ -123,12 +154,12 @@ abstract class AbstractStyle /** * Set style by using associative array * - * @param array $styles + * @param array $values * @return self */ - public function setStyleByArray($styles = array()) + public function setStyleByArray($values = array()) { - foreach ($styles as $key => $value) { + foreach ($values as $key => $value) { $this->setStyleValue($key, $value); } @@ -138,13 +169,13 @@ abstract class AbstractStyle /** * Set default for null and empty value * - * @param mixed $value - * @param mixed $default - * @return mixed + * @param string $value (was: mixed) + * @param string $default (was: mixed) + * @return string (was: mixed) */ protected function setNonEmptyVal($value, $default) { - if (is_null($value) || $value == '') { + if ($value === null || $value == '') { $value = $default; } @@ -152,13 +183,13 @@ abstract class AbstractStyle } /** - * Set boolean value + * Set bool value * - * @param mixed $value - * @param boolean|null $default - * @return boolean|null + * @param bool $value + * @param bool $default + * @return bool */ - protected function setBoolVal($value, $default = null) + protected function setBoolVal($value, $default) { if (!is_bool($value)) { $value = $default; @@ -184,9 +215,9 @@ abstract class AbstractStyle } /** - * Set float value: Convert string that contains only numeric into integer + * Set integer value: Convert string that contains only numeric into integer * - * @param mixed $value + * @param int|null $value * @param int|null $default * @return int|null */ @@ -227,6 +258,8 @@ abstract class AbstractStyle * @param mixed $value * @param array $enum * @param mixed $default + * @return mixed + * @throws \InvalidArgumentException */ protected function setEnumVal($value = null, $enum = array(), $default = null) { @@ -245,11 +278,13 @@ abstract class AbstractStyle * @param mixed $value * @param string $styleName * @param mixed $style + * @return mixed */ protected function setObjectVal($value, $styleName, &$style) { $styleClass = substr(get_class($this), 0, strrpos(get_class($this), '\\')) . '\\' . $styleName; if (is_array($value)) { + /** @var \PhpOffice\PhpWord\Style\AbstractStyle $style Type hint */ if (!$style instanceof $styleClass) { $style = new $styleClass(); } @@ -265,6 +300,7 @@ abstract class AbstractStyle * Set style using associative array * * @param array $style + * @return self * @deprecated 0.11.0 * @codeCoverageIgnore */ diff --git a/src/PhpWord/Style/Alignment.php b/src/PhpWord/Style/Alignment.php new file mode 100644 index 00000000..3beabe37 --- /dev/null +++ b/src/PhpWord/Style/Alignment.php @@ -0,0 +1,78 @@ +setStyleByArray($style); + } + + /** + * Get alignment + * + * @return string + */ + public function getValue() + { + return $this->value; + } + + /** + * Set alignment + * + * @param string $value + * @return self + */ + public function setValue($value = null) + { + if (strtolower($value) == self::ALIGN_JUSTIFY) { + $value = self::ALIGN_BOTH; + } + $enum = array(self::ALIGN_LEFT, self::ALIGN_RIGHT, self::ALIGN_CENTER, self::ALIGN_BOTH, self::ALIGN_JUSTIFY); + $this->value = $this->setEnumVal($value, $enum, $this->value); + + return $this; + } +} diff --git a/src/PhpWord/Style/Border.php b/src/PhpWord/Style/Border.php index f7c479fe..f0fd8650 100644 --- a/src/PhpWord/Style/Border.php +++ b/src/PhpWord/Style/Border.php @@ -78,22 +78,6 @@ class Border extends AbstractStyle */ protected $borderBottomColor; - /** - * Set border size - * - * @param int|float $value - * @return self - */ - public function setBorderSize($value = null) - { - $this->setBorderTopSize($value); - $this->setBorderLeftSize($value); - $this->setBorderRightSize($value); - $this->setBorderBottomSize($value); - - return $this; - } - /** * Get border size * @@ -110,17 +94,17 @@ class Border extends AbstractStyle } /** - * Set border color + * Set border size * - * @param string $value + * @param int|float $value * @return self */ - public function setBorderColor($value = null) + public function setBorderSize($value = null) { - $this->setBorderTopColor($value); - $this->setBorderLeftColor($value); - $this->setBorderRightColor($value); - $this->setBorderBottomColor($value); + $this->setBorderTopSize($value); + $this->setBorderLeftSize($value); + $this->setBorderRightSize($value); + $this->setBorderBottomSize($value); return $this; } @@ -141,14 +125,17 @@ class Border extends AbstractStyle } /** - * Set border top size + * Set border color * - * @param int|float $value + * @param string $value * @return self */ - public function setBorderTopSize($value = null) + public function setBorderColor($value = null) { - $this->borderTopSize = $value; + $this->setBorderTopColor($value); + $this->setBorderLeftColor($value); + $this->setBorderRightColor($value); + $this->setBorderBottomColor($value); return $this; } @@ -163,6 +150,29 @@ class Border extends AbstractStyle return $this->borderTopSize; } + /** + * Set border top size + * + * @param int|float $value + * @return self + */ + public function setBorderTopSize($value = null) + { + $this->borderTopSize = $this->setNumericVal($value, $this->borderTopSize); + + return $this; + } + + /** + * Get border top color + * + * @return string + */ + public function getBorderTopColor() + { + return $this->borderTopColor; + } + /** * Set border top color * @@ -177,13 +187,13 @@ class Border extends AbstractStyle } /** - * Get border top color + * Get border left size * - * @return string + * @return int|float */ - public function getBorderTopColor() + public function getBorderLeftSize() { - return $this->borderTopColor; + return $this->borderLeftSize; } /** @@ -194,19 +204,19 @@ class Border extends AbstractStyle */ public function setBorderLeftSize($value = null) { - $this->borderLeftSize = $value; + $this->borderLeftSize = $this->setNumericVal($value, $this->borderLeftSize); return $this; } /** - * Get border left size + * Get border left color * - * @return int|float + * @return string */ - public function getBorderLeftSize() + public function getBorderLeftColor() { - return $this->borderLeftSize; + return $this->borderLeftColor; } /** @@ -223,13 +233,13 @@ class Border extends AbstractStyle } /** - * Get border left color + * Get border right size * - * @return string + * @return int|float */ - public function getBorderLeftColor() + public function getBorderRightSize() { - return $this->borderLeftColor; + return $this->borderRightSize; } /** @@ -240,19 +250,19 @@ class Border extends AbstractStyle */ public function setBorderRightSize($value = null) { - $this->borderRightSize = $value; + $this->borderRightSize = $this->setNumericVal($value, $this->borderRightSize); return $this; } /** - * Get border right size + * Get border right color * - * @return int|float + * @return string */ - public function getBorderRightSize() + public function getBorderRightColor() { - return $this->borderRightSize; + return $this->borderRightColor; } /** @@ -269,13 +279,13 @@ class Border extends AbstractStyle } /** - * Get border right color + * Get border bottom size * - * @return string + * @return int|float */ - public function getBorderRightColor() + public function getBorderBottomSize() { - return $this->borderRightColor; + return $this->borderBottomSize; } /** @@ -286,19 +296,19 @@ class Border extends AbstractStyle */ public function setBorderBottomSize($value = null) { - $this->borderBottomSize = $value; + $this->borderBottomSize = $this->setNumericVal($value, $this->borderBottomSize); return $this; } /** - * Get border bottom size + * Get border bottom color * - * @return int|float + * @return string */ - public function getBorderBottomSize() + public function getBorderBottomColor() { - return $this->borderBottomSize; + return $this->borderBottomColor; } /** @@ -315,30 +325,14 @@ class Border extends AbstractStyle } /** - * Get border bottom color - * - * @return string - */ - public function getBorderBottomColor() - { - return $this->borderBottomColor; - } - - /** - * Has borders? + * Check if any of the border is not null * * @return bool */ - public function hasBorders() + public function hasBorder() { - $hasBorders = false; $borders = $this->getBorderSize(); - for ($i = 0; $i < count($borders); $i++) { - if (!is_null($borders[$i])) { - $hasBorders = true; - } - } - return $hasBorders; + return $borders !== array_filter($borders, 'is_null'); } } diff --git a/src/PhpWord/Style/Cell.php b/src/PhpWord/Style/Cell.php index e44ffa38..95ed13b4 100644 --- a/src/PhpWord/Style/Cell.php +++ b/src/PhpWord/Style/Cell.php @@ -146,6 +146,8 @@ class Cell extends Border { if (!is_null($this->shading)) { return $this->shading->getFill(); + } else { + return null; } } diff --git a/src/PhpWord/Style/Font.php b/src/PhpWord/Style/Font.php index 32874b2f..07eebdb2 100644 --- a/src/PhpWord/Style/Font.php +++ b/src/PhpWord/Style/Font.php @@ -17,8 +17,6 @@ namespace PhpOffice\PhpWord\Style; -use PhpOffice\PhpWord\PhpWord; - /** * Font style */ @@ -86,30 +84,30 @@ class Font extends AbstractStyle /** * Font name * - * @var int|float + * @var string */ - private $name = PhpWord::DEFAULT_FONT_NAME; + private $name; /** * Font Content Type * * @var string */ - private $hint = PhpWord::DEFAULT_FONT_CONTENT_TYPE; + private $hint; /** * Font size * * @var int|float */ - private $size = PhpWord::DEFAULT_FONT_SIZE; + private $size; /** * Font color * * @var string */ - private $color = PhpWord::DEFAULT_FONT_COLOR; + private $color; /** * Bold @@ -241,9 +239,9 @@ class Font extends AbstractStyle * @param string $value * @return self */ - public function setName($value = PhpWord::DEFAULT_FONT_NAME) + public function setName($value = null) { - $this->name = $this->setNonEmptyVal($value, PhpWord::DEFAULT_FONT_NAME); + $this->name = $value; return $this; } @@ -264,9 +262,9 @@ class Font extends AbstractStyle * @param string $value * @return self */ - public function setHint($value = PhpWord::DEFAULT_FONT_CONTENT_TYPE) + public function setHint($value = null) { - $this->hint = $this->setNonEmptyVal($value, PhpWord::DEFAULT_FONT_CONTENT_TYPE); + $this->hint = $value; return $this; } @@ -287,9 +285,9 @@ class Font extends AbstractStyle * @param int|float $value * @return self */ - public function setSize($value = PhpWord::DEFAULT_FONT_SIZE) + public function setSize($value = null) { - $this->size = $this->setNumericVal($value, PhpWord::DEFAULT_FONT_SIZE); + $this->size = $this->setNumericVal($value, $this->size); return $this; } @@ -310,9 +308,9 @@ class Font extends AbstractStyle * @param string $value * @return self */ - public function setColor($value = PhpWord::DEFAULT_FONT_COLOR) + public function setColor($value = null) { - $this->color = $this->setNonEmptyVal($value, PhpWord::DEFAULT_FONT_COLOR); + $this->color = $value; return $this; } @@ -333,7 +331,7 @@ class Font extends AbstractStyle * @param bool $value * @return self */ - public function setBold($value = false) + public function setBold($value = true) { $this->bold = $this->setBoolVal($value, $this->bold); @@ -356,7 +354,7 @@ class Font extends AbstractStyle * @param bool $value * @return self */ - public function setItalic($value = false) + public function setItalic($value = true) { $this->italic = $this->setBoolVal($value, $this->italic); @@ -402,12 +400,9 @@ class Font extends AbstractStyle * @param bool $value * @return self */ - public function setSuperScript($value = false) + public function setSuperScript($value = true) { - $this->superScript = $this->setBoolVal($value, $this->superScript); - $this->toggleFalse($this->subScript, $this->superScript); - - return $this; + return $this->setPairedProperty($this->superScript, $this->subScript, $value); } /** @@ -426,15 +421,9 @@ class Font extends AbstractStyle * @param bool $value * @return self */ - public function setSubScript($value = false) + public function setSubScript($value = true) { - $this->subScript = $this->setBoolVal($value, $this->subScript); - $this->toggleFalse($this->subScript, $this->superScript); - if ($this->subScript) { - $this->superScript = false; - } - - return $this; + return $this->setPairedProperty($this->subScript, $this->superScript, $value); } /** @@ -453,12 +442,9 @@ class Font extends AbstractStyle * @param bool $value * @return self */ - public function setStrikethrough($value = false) + public function setStrikethrough($value = true) { - $this->strikethrough = $this->setBoolVal($value, $this->strikethrough); - $this->toggleFalse($this->doubleStrikethrough, $this->strikethrough); - - return $this; + return $this->setPairedProperty($this->strikethrough, $this->doubleStrikethrough, $value); } /** @@ -477,12 +463,9 @@ class Font extends AbstractStyle * @param bool $value * @return self */ - public function setDoubleStrikethrough($value = false) + public function setDoubleStrikethrough($value = true) { - $this->doubleStrikethrough = $this->setBoolVal($value, $this->doubleStrikethrough); - $this->toggleFalse($this->strikethrough, $this->doubleStrikethrough); - - return $this; + return $this->setPairedProperty($this->doubleStrikethrough, $this->strikethrough, $value); } /** @@ -501,12 +484,9 @@ class Font extends AbstractStyle * @param bool $value * @return self */ - public function setSmallCaps($value = false) + public function setSmallCaps($value = true) { - $this->smallCaps = $this->setBoolVal($value, $this->smallCaps); - $this->toggleFalse($this->allCaps, $this->smallCaps); - - return $this; + return $this->setPairedProperty($this->smallCaps, $this->allCaps, $value); } /** @@ -525,12 +505,9 @@ class Font extends AbstractStyle * @param bool $value * @return self */ - public function setAllCaps($value = false) + public function setAllCaps($value = true) { - $this->allCaps = $this->setBoolVal($value, $this->allCaps); - $this->toggleFalse($this->smallCaps, $this->allCaps); - - return $this; + return $this->setPairedProperty($this->allCaps, $this->smallCaps, $value); } /** @@ -565,6 +542,8 @@ class Font extends AbstractStyle { if (!is_null($this->shading)) { return $this->shading->getFill(); + } else { + return null; } } @@ -649,16 +628,21 @@ class Font extends AbstractStyle } /** - * Toggle $target property to false when $source true + * Set $property value and set $pairProperty = false when $value = true * - * @param bool $target Target property - * @param bool $sourceValue + * @param bool $property + * @param bool $pairProperty + * @param bool $value + * @return self */ - private function toggleFalse(&$target, $sourceValue) + private function setPairedProperty(&$property, &$pairProperty, $value) { - if ($sourceValue == true) { - $target = false; + $property = $this->setBoolVal($value, $property); + if ($value == true) { + $pairProperty = false; } + + return $this; } /** diff --git a/src/PhpWord/Style/Image.php b/src/PhpWord/Style/Image.php index 5dc82d0b..fc9f9630 100644 --- a/src/PhpWord/Style/Image.php +++ b/src/PhpWord/Style/Image.php @@ -94,9 +94,9 @@ class Image extends AbstractStyle /** * Alignment * - * @var string + * @var \PhpOffice\PhpWord\Style\Alignment */ - private $align; + private $alignment; /** * Margin Top @@ -154,8 +154,18 @@ class Image extends AbstractStyle */ private $posVerticalRel = self::POSITION_RELATIVE_TO_LINE; + /** + * Create new instance + */ + public function __construct() + { + $this->alignment = new Alignment(); + } + /** * Get width + * + * @return int */ public function getWidth() { @@ -166,14 +176,19 @@ class Image extends AbstractStyle * Set width * * @param int $value + * @return self */ public function setWidth($value = null) { $this->width = $value; + + return $this; } /** * Get height + * + * @return int */ public function getHeight() { @@ -184,32 +199,40 @@ class Image extends AbstractStyle * Set height * * @param int $value + * @return self */ public function setHeight($value = null) { $this->height = $value; + + return $this; } /** * Get alignment + * + * @return string */ public function getAlign() { - return $this->align; + return $this->alignment->getValue(); } /** * Set alignment * * @param string $value + * @return self */ public function setAlign($value = null) { - $this->align = $value; + $this->alignment->setValue($value); + + return $this; } /** - * Get Margin Top + * Get margin top * * @return int */ @@ -219,7 +242,7 @@ class Image extends AbstractStyle } /** - * Set Margin Top + * Set margin top * * @param int $value * @return self @@ -227,11 +250,12 @@ class Image extends AbstractStyle public function setMarginTop($value = null) { $this->marginTop = $value; + return $this; } /** - * Get Margin Left + * Get margin left * * @return int */ @@ -241,7 +265,7 @@ class Image extends AbstractStyle } /** - * Set Margin Left + * Set margin left * * @param int $value * @return self @@ -249,6 +273,7 @@ class Image extends AbstractStyle public function setMarginLeft($value = null) { $this->marginLeft = $value; + return $this; } diff --git a/src/PhpWord/Style/Paragraph.php b/src/PhpWord/Style/Paragraph.php index 79a12242..8609b5ab 100644 --- a/src/PhpWord/Style/Paragraph.php +++ b/src/PhpWord/Style/Paragraph.php @@ -25,6 +25,9 @@ use PhpOffice\PhpWord\Shared\String; */ class Paragraph extends AbstractStyle { + /** + * @const int One line height equals 240 twip + */ const LINE_HEIGHT = 240; /** @@ -34,13 +37,6 @@ class Paragraph extends AbstractStyle */ protected $aliases = array('line-height' => 'lineHeight'); - /** - * Paragraph alignment - * - * @var string - */ - private $align; - /** * Text line height * @@ -111,11 +107,27 @@ class Paragraph extends AbstractStyle */ private $spacing; + /** + * Alignment + * + * @var \PhpOffice\PhpWord\Style\Alignment + */ + private $alignment; + + /** + * Create new instance + */ + public function __construct() + { + $this->alignment = new Alignment(); + } + /** * Set Style value * * @param string $key * @param mixed $value + * @return self */ public function setStyleValue($key, $value) { @@ -130,27 +142,24 @@ class Paragraph extends AbstractStyle } /** - * Get Paragraph Alignment + * Get alignment * * @return string */ public function getAlign() { - return $this->align; + return $this->alignment->getValue(); } /** - * Set Paragraph Alignment + * Set alignment * * @param string $value * @return self */ public function setAlign($value = null) { - if (strtolower($value) == 'justify') { - $value = 'both'; - } - $this->align = $value; + $this->alignment->setValue($value); return $this; } @@ -164,6 +173,8 @@ class Paragraph extends AbstractStyle { if (!is_null($this->spacing)) { return $this->spacing->getBefore(); + } else { + return null; } } @@ -187,6 +198,8 @@ class Paragraph extends AbstractStyle { if (!is_null($this->spacing)) { return $this->spacing->getAfter(); + } else { + return null; } } @@ -210,6 +223,8 @@ class Paragraph extends AbstractStyle { if (!is_null($this->spacing)) { return $this->spacing->getLine(); + } else { + return null; } } @@ -238,7 +253,7 @@ class Paragraph extends AbstractStyle * Set the line height * * @param int|float|string $lineHeight - * @return $this + * @return self * @throws \PhpOffice\PhpWord\Exception\InvalidStyleException */ public function setLineHeight($lineHeight) @@ -265,6 +280,8 @@ class Paragraph extends AbstractStyle { if (!is_null($this->indentation)) { return $this->indentation->getLeft(); + } else { + return null; } } @@ -288,6 +305,8 @@ class Paragraph extends AbstractStyle { if (!is_null($this->indentation)) { return $this->indentation->getHanging(); + } else { + return null; } } @@ -412,7 +431,7 @@ class Paragraph extends AbstractStyle * @param bool $value * @return self */ - public function setKeepNext($value = false) + public function setKeepNext($value = true) { $this->keepNext = $this->setBoolVal($value, $this->keepNext); @@ -435,7 +454,7 @@ class Paragraph extends AbstractStyle * @param bool $value * @return self */ - public function setKeepLines($value = false) + public function setKeepLines($value = true) { $this->keepLines = $this->setBoolVal($value, $this->keepLines); @@ -458,7 +477,7 @@ class Paragraph extends AbstractStyle * @param bool $value * @return self */ - public function setPageBreakBefore($value = false) + public function setPageBreakBefore($value = true) { $this->pageBreakBefore = $this->setBoolVal($value, $this->pageBreakBefore); diff --git a/src/PhpWord/Style/Row.php b/src/PhpWord/Style/Row.php index 310564d8..45897aed 100644 --- a/src/PhpWord/Style/Row.php +++ b/src/PhpWord/Style/Row.php @@ -68,7 +68,7 @@ class Row extends AbstractStyle * @param bool $value * @return self */ - public function setTblHeader($value = false) + public function setTblHeader($value = true) { $this->tblHeader = $this->setBoolVal($value, $this->tblHeader); @@ -91,7 +91,7 @@ class Row extends AbstractStyle * @param bool $value * @return self */ - public function setCantSplit($value = false) + public function setCantSplit($value = true) { $this->cantSplit = $this->setBoolVal($value, $this->cantSplit); @@ -114,7 +114,7 @@ class Row extends AbstractStyle * @param bool $value * @return self */ - public function setExactHeight($value = false) + public function setExactHeight($value = true) { $this->exactHeight = $this->setBoolVal($value, $this->exactHeight); diff --git a/src/PhpWord/Style/Section.php b/src/PhpWord/Style/Section.php index 8a0c071d..fd59f1b4 100644 --- a/src/PhpWord/Style/Section.php +++ b/src/PhpWord/Style/Section.php @@ -181,15 +181,19 @@ class Section extends Border { $enum = array(self::ORIENTATION_PORTRAIT, self::ORIENTATION_LANDSCAPE); $this->orientation = $this->setEnumVal($value, $enum, $this->orientation); - $longSize = $this->pageSizeW >= $this->pageSizeH ? $this->pageSizeW : $this->pageSizeH; - $shortSize = $this->pageSizeW < $this->pageSizeH ? $this->pageSizeW : $this->pageSizeH; + + /** @var int|float $longSide Type hint */ + $longSide = $this->pageSizeW >= $this->pageSizeH ? $this->pageSizeW : $this->pageSizeH; + + /** @var int|float $shortSide Type hint */ + $shortSide = $this->pageSizeW < $this->pageSizeH ? $this->pageSizeW : $this->pageSizeH; if ($this->orientation == self::ORIENTATION_PORTRAIT) { - $this->pageSizeW = $shortSize; - $this->pageSizeH = $longSize; + $this->pageSizeW = $shortSide; + $this->pageSizeH = $longSide; } else { - $this->pageSizeW = $longSize; - $this->pageSizeH = $shortSize; + $this->pageSizeW = $longSide; + $this->pageSizeH = $shortSide; } return $this; @@ -420,7 +424,7 @@ class Section extends Border * Set page numbering start * * @param null|int $pageNumberingStart - * @return $this + * @return self */ public function setPageNumberingStart($pageNumberingStart = null) { diff --git a/src/PhpWord/Style/Table.php b/src/PhpWord/Style/Table.php index c9850e73..68b53463 100644 --- a/src/PhpWord/Style/Table.php +++ b/src/PhpWord/Style/Table.php @@ -22,40 +22,54 @@ namespace PhpOffice\PhpWord\Style; */ class Table extends Border { + /** + * @const string Table width units http://www.schemacentral.com/sc/ooxml/t-w_ST_TblWidth.html + */ + const WIDTH_AUTO = 'auto'; // Automatically determined width + const WIDTH_PERCENT = 'pct'; // Width in fiftieths (1/50) of a percent (1% = 50 unit) + const WIDTH_TWIP = 'dxa'; // Width in twentieths (1/20) of a point (twip) + + /** + * Is this a first row style? + * + * @var bool + */ + private $isFirstRow = false; + /** * Style for first row * * @var \PhpOffice\PhpWord\Style\Table */ - private $firstRow = null; + private $firstRowStyle; /** * Cell margin top * * @var int */ - private $cellMarginTop = null; + private $cellMarginTop; /** * Cell margin left * * @var int */ - private $cellMarginLeft = null; + private $cellMarginLeft; /** * Cell margin right * * @var int */ - private $cellMarginRight = null; + private $cellMarginRight; /** * Cell margin bottom * * @var int */ - private $cellMarginBottom = null; + private $cellMarginBottom; /** * Border size inside horizontal @@ -92,42 +106,60 @@ class Table extends Border */ private $shading; + /** + * @var \PhpOffice\PhpWord\Style\Alignment Alignment + */ + private $alignment; + + /** + * @var int|float Width value + */ + private $width = 0; + + /** + * @var string Width unit + */ + private $unit = self::WIDTH_AUTO; + /** * Create new table style * - * @param mixed $styleTable - * @param mixed $styleFirstRow + * @param mixed $tableStyle + * @param mixed $firstRowStyle */ - public function __construct($styleTable = null, $styleFirstRow = null) + public function __construct($tableStyle = null, $firstRowStyle = null) { - if (!is_null($styleFirstRow) && is_array($styleFirstRow)) { - $this->firstRow = clone $this; + $this->alignment = new Alignment(); - unset($this->firstRow->firstRow); - unset($this->firstRow->cellMarginBottom); - unset($this->firstRow->cellMarginTop); - unset($this->firstRow->cellMarginLeft); - unset($this->firstRow->cellMarginRight); - unset($this->firstRow->borderInsideVColor); - unset($this->firstRow->borderInsideVSize); - unset($this->firstRow->borderInsideHColor); - unset($this->firstRow->borderInsideHSize); - $this->firstRow->setStyleByArray($styleFirstRow); + // Clone first row from table style, but with certain properties disabled + if ($firstRowStyle !== null && is_array($firstRowStyle)) { + $this->firstRowStyle = clone $this; + $this->firstRowStyle->isFirstRow = true; + unset($this->firstRowStyle->firstRowStyle); + unset($this->firstRowStyle->borderInsideHSize); + unset($this->firstRowStyle->borderInsideHColor); + unset($this->firstRowStyle->borderInsideVSize); + unset($this->firstRowStyle->borderInsideVColor); + unset($this->firstRowStyle->cellMarginTop); + unset($this->firstRowStyle->cellMarginLeft); + unset($this->firstRowStyle->cellMarginRight); + unset($this->firstRowStyle->cellMarginBottom); + $this->firstRowStyle->setStyleByArray($firstRowStyle); } - if (!is_null($styleTable) && is_array($styleTable)) { - $this->setStyleByArray($styleTable); + if ($tableStyle !== null && is_array($tableStyle)) { + $this->setStyleByArray($tableStyle); } } /** - * Get First Row Style + * Set first row * * @return \PhpOffice\PhpWord\Style\Table */ public function getFirstRow() { - return $this->firstRow; + return $this->firstRowStyle; } /** @@ -139,36 +171,20 @@ class Table extends Border { if (!is_null($this->shading)) { return $this->shading->getFill(); - } else { - return null; } + + return null; } /** * Set background * * @param string $value - * @return \PhpOffice\PhpWord\Style\Table + * @return self */ public function setBgColor($value = null) { $this->setShading(array('fill' => $value)); - } - - /** - * Set TLRBHV Border Size - * - * @param int $value Border size in eighths of a point (1/8 point) - * @return self - */ - public function setBorderSize($value = null) - { - $this->setBorderTopSize($value); - $this->setBorderLeftSize($value); - $this->setBorderRightSize($value); - $this->setBorderBottomSize($value); - $this->setBorderInsideHSize($value); - $this->setBorderInsideVSize($value); return $this; } @@ -191,19 +207,19 @@ class Table extends Border } /** - * Set TLRBHV Border Color + * Set TLRBHV Border Size * - * @param string $value + * @param int $value Border size in eighths of a point (1/8 point) * @return self */ - public function setBorderColor($value = null) + public function setBorderSize($value = null) { - $this->setBorderTopColor($value); - $this->setBorderLeftColor($value); - $this->setBorderRightColor($value); - $this->setBorderBottomColor($value); - $this->setBorderInsideHColor($value); - $this->setBorderInsideVColor($value); + $this->setBorderTopSize($value); + $this->setBorderLeftSize($value); + $this->setBorderRightSize($value); + $this->setBorderBottomSize($value); + $this->setBorderInsideHSize($value); + $this->setBorderInsideVSize($value); return $this; } @@ -226,13 +242,21 @@ class Table extends Border } /** - * Set border size inside horizontal + * Set TLRBHV Border Color * - * @param int $value + * @param string $value + * @return self */ - public function setBorderInsideHSize($value = null) + public function setBorderColor($value = null) { - $this->borderInsideHSize = $value; + $this->setBorderTopColor($value); + $this->setBorderLeftColor($value); + $this->setBorderRightColor($value); + $this->setBorderBottomColor($value); + $this->setBorderInsideHColor($value); + $this->setBorderInsideVColor($value); + + return $this; } /** @@ -242,37 +266,18 @@ class Table extends Border */ public function getBorderInsideHSize() { - return (isset($this->borderInsideHSize)) ? $this->borderInsideHSize : null; + return $this->getTableOnlyProperty('borderInsideHSize'); } /** - * Set border size inside vertical + * Set border size inside horizontal * * @param int $value + * @return self */ - public function setBorderInsideVSize($value = null) + public function setBorderInsideHSize($value = null) { - $this->borderInsideVSize = $value; - } - - /** - * Get border size inside vertical - * - * @return int - */ - public function getBorderInsideVSize() - { - return (isset($this->borderInsideVSize)) ? $this->borderInsideVSize : null; - } - - /** - * Set border color inside horizontal - * - * @param string $value - */ - public function setBorderInsideHColor($value = null) - { - $this->borderInsideHColor = $value; + return $this->setTableOnlyProperty('borderInsideHSize', $value); } /** @@ -282,17 +287,39 @@ class Table extends Border */ public function getBorderInsideHColor() { - return (isset($this->borderInsideHColor)) ? $this->borderInsideHColor : null; + return $this->getTableOnlyProperty('borderInsideHColor'); } /** - * Set border color inside vertical + * Set border color inside horizontal * * @param string $value + * @return self */ - public function setBorderInsideVColor($value = null) + public function setBorderInsideHColor($value = null) { - $this->borderInsideVColor = $value; + return $this->setTableOnlyProperty('borderInsideHColor', $value, false); + } + + /** + * Get border size inside vertical + * + * @return int + */ + public function getBorderInsideVSize() + { + return $this->getTableOnlyProperty('borderInsideVSize'); + } + + /** + * Set border size inside vertical + * + * @param int $value + * @return self + */ + public function setBorderInsideVSize($value = null) + { + return $this->setTableOnlyProperty('borderInsideVSize', $value); } /** @@ -302,17 +329,18 @@ class Table extends Border */ public function getBorderInsideVColor() { - return (isset($this->borderInsideVColor)) ? $this->borderInsideVColor : null; + return $this->getTableOnlyProperty('borderInsideVColor'); } /** - * Set cell margin top + * Set border color inside vertical * - * @param int $value + * @param string $value + * @return self */ - public function setCellMarginTop($value = null) + public function setBorderInsideVColor($value = null) { - $this->cellMarginTop = $value; + return $this->setTableOnlyProperty('borderInsideVColor', $value, false); } /** @@ -322,17 +350,18 @@ class Table extends Border */ public function getCellMarginTop() { - return $this->cellMarginTop; + return $this->getTableOnlyProperty('cellMarginTop'); } /** - * Set cell margin left + * Set cell margin top * * @param int $value + * @return self */ - public function setCellMarginLeft($value = null) + public function setCellMarginTop($value = null) { - $this->cellMarginLeft = $value; + return $this->setTableOnlyProperty('cellMarginTop', $value); } /** @@ -342,17 +371,18 @@ class Table extends Border */ public function getCellMarginLeft() { - return $this->cellMarginLeft; + return $this->getTableOnlyProperty('cellMarginLeft'); } /** - * Set cell margin right + * Set cell margin left * * @param int $value + * @return self */ - public function setCellMarginRight($value = null) + public function setCellMarginLeft($value = null) { - $this->cellMarginRight = $value; + return $this->setTableOnlyProperty('cellMarginLeft', $value); } /** @@ -362,17 +392,18 @@ class Table extends Border */ public function getCellMarginRight() { - return $this->cellMarginRight; + return $this->getTableOnlyProperty('cellMarginRight'); } /** - * Set cell margin bottom + * Set cell margin right * * @param int $value + * @return self */ - public function setCellMarginBottom($value = null) + public function setCellMarginRight($value = null) { - $this->cellMarginBottom = $value; + return $this->setTableOnlyProperty('cellMarginRight', $value); } /** @@ -382,13 +413,40 @@ class Table extends Border */ public function getCellMarginBottom() { - return $this->cellMarginBottom; + return $this->getTableOnlyProperty('cellMarginBottom'); + } + + /** + * Set cell margin bottom + * + * @param int $value + * @return self + */ + public function setCellMarginBottom($value = null) + { + return $this->setTableOnlyProperty('cellMarginBottom', $value); + } + + /** + * Get cell margin + * + * @return integer[] + */ + public function getCellMargin() + { + return array( + $this->cellMarginTop, + $this->cellMarginLeft, + $this->cellMarginRight, + $this->cellMarginBottom + ); } /** * Set TLRB cell margin * * @param int $value Margin in twips + * @return self */ public function setCellMargin($value = null) { @@ -396,16 +454,20 @@ class Table extends Border $this->setCellMarginLeft($value); $this->setCellMarginRight($value); $this->setCellMarginBottom($value); + + return $this; } /** - * Get cell margin + * Check if any of the margin is not null * - * @return int[] + * @return bool */ - public function getCellMargin() + public function hasMargin() { - return array($this->cellMarginTop, $this->cellMarginLeft, $this->cellMarginRight, $this->cellMarginBottom); + $margins = $this->getCellMargin(); + + return $margins !== array_filter($margins, 'is_null'); } /** @@ -432,20 +494,114 @@ class Table extends Border } /** - * Has margins? + * Get alignment * - * @return bool + * @return string */ - public function hasMargins() + public function getAlign() { - $hasMargins = false; - $margins = $this->getCellMargin(); - for ($i = 0; $i < count($margins); $i++) { - if (!is_null($margins[$i])) { - $hasMargins = true; + return $this->alignment->getValue(); + } + + /** + * Set alignment + * + * @param string $value + * @return self + */ + public function setAlign($value = null) + { + $this->alignment->setValue($value); + + return $this; + } + + /** + * Get width + * + * @return int|float + */ + public function getWidth() + { + return $this->width; + } + + /** + * Set width + * + * @param int|float $value + * @return self + */ + public function setWidth($value = null) + { + $this->width = $this->setNumericVal($value, $this->width); + + return $this; + } + + /** + * Get width unit + * + * @return string + */ + public function getUnit() + { + return $this->unit; + } + + /** + * Set width unit + * + * @param string $value + * @return self + */ + public function setUnit($value = null) + { + $enum = array(self::WIDTH_AUTO, self::WIDTH_PERCENT, self::WIDTH_TWIP); + $this->unit = $this->setEnumVal($value, $enum, $this->unit); + + return $this; + } + + /** + * Get table style only property by checking if it's a firstRow + * + * This is necessary since firstRow style is cloned from table style but + * without certain properties activated, e.g. margins + * + * @param string $property + * @return int|string|null + */ + private function getTableOnlyProperty($property) + { + if ($this->isFirstRow === false) { + return $this->$property; + } + + return null; + } + + /** + * Set table style only property by checking if it's a firstRow + * + * This is necessary since firstRow style is cloned from table style but + * without certain properties activated, e.g. margins + * + * @param string $property + * @param int|string $value + * @param bool $isNumeric + * @return self + */ + private function setTableOnlyProperty($property, $value, $isNumeric = true) + { + if ($this->isFirstRow === false) { + if ($isNumeric === true) { + $this->$property = $this->setNumericVal($value, $this->$property); + } else { + $this->$property = $value; } } - return $hasMargins; + return $this; } } diff --git a/src/PhpWord/Template.php b/src/PhpWord/Template.php index 68550cfe..21e8b988 100644 --- a/src/PhpWord/Template.php +++ b/src/PhpWord/Template.php @@ -19,6 +19,7 @@ namespace PhpOffice\PhpWord; use PhpOffice\PhpWord\Exception\Exception; use PhpOffice\PhpWord\Shared\String; +use PhpOffice\PhpWord\Shared\ZipArchive; /** * Template @@ -78,8 +79,7 @@ class Template throw new Exception("Could not copy the template from {$strFilename} to {$this->tempFileName}."); } - $zipClass = Settings::getZipClass(); - $this->zipClass = new $zipClass(); + $this->zipClass = new ZipArchive(); $this->zipClass->open($this->tempFileName); // Find and load headers and footers diff --git a/src/PhpWord/Writer/AbstractWriter.php b/src/PhpWord/Writer/AbstractWriter.php index f1a30026..52a1a28c 100644 --- a/src/PhpWord/Writer/AbstractWriter.php +++ b/src/PhpWord/Writer/AbstractWriter.php @@ -19,7 +19,7 @@ namespace PhpOffice\PhpWord\Writer; use PhpOffice\PhpWord\Exception\Exception; use PhpOffice\PhpWord\PhpWord; -use PhpOffice\PhpWord\Settings; +use PhpOffice\PhpWord\Shared\ZipArchive; /** * Abstract writer class @@ -149,6 +149,7 @@ abstract class AbstractWriter implements WriterInterface * @param bool $value * @param string $directory * @return self + * @throws \PhpOffice\PhpWord\Exception\Exception */ public function setUseDiskCaching($value = false, $directory = null) { @@ -256,41 +257,34 @@ abstract class AbstractWriter implements WriterInterface * Get ZipArchive object * * @param string $filename - * @return mixed ZipArchive object + * @return \PhpOffice\PhpWord\Shared\ZipArchive + * @throws \PhpOffice\PhpWord\Exception\Exception */ protected function getZipArchive($filename) { - // Create new ZIP file and open it for writing - $zipClass = Settings::getZipClass(); - $objZip = new $zipClass(); - - // Retrieve OVERWRITE and CREATE constants from the instantiated zip class - $reflection = new \ReflectionObject($objZip); - $zipOverWrite = $reflection->getConstant('OVERWRITE'); - $zipCreate = $reflection->getConstant('CREATE'); - // Remove any existing file if (file_exists($filename)) { unlink($filename); } // Try opening the ZIP file - if ($objZip->open($filename, $zipOverWrite) !== true) { - if ($objZip->open($filename, $zipCreate) !== true) { + $zip = new ZipArchive(); + if ($zip->open($filename, ZipArchive::OVERWRITE) !== true) { + if ($zip->open($filename, ZipArchive::CREATE) !== true) { throw new Exception("Could not open " . $filename . " for writing."); } } - return $objZip; + return $zip; } /** * Add files to package * - * @param mixed $objZip + * @param \PhpOffice\PhpWord\Shared\ZipArchive $zip * @param mixed $elements */ - protected function addFilesToPackage($objZip, $elements) + protected function addFilesToPackage(ZipArchive $zip, $elements) { foreach ($elements as $element) { $type = $element['type']; // image|object|link @@ -308,10 +302,10 @@ abstract class AbstractWriter implements WriterInterface call_user_func($element['imageFunction'], $image); $imageContents = ob_get_contents(); ob_end_clean(); - $objZip->addFromString($target, $imageContents); + $zip->addFromString($target, $imageContents); imagedestroy($image); } else { - $this->addFileToPackage($objZip, $element['source'], $target); + $this->addFileToPackage($zip, $element['source'], $target); } } } @@ -321,11 +315,11 @@ abstract class AbstractWriter implements WriterInterface * * Get the actual source from an archive image * - * @param mixed $objZip + * @param \PhpOffice\PhpWord\Shared\ZipArchive $zipPackage * @param string $source * @param string $target */ - protected function addFileToPackage($objZip, $source, $target) + protected function addFileToPackage($zipPackage, $source, $target) { $isArchive = strpos($source, 'zip://') !== false; $actualSource = null; @@ -333,8 +327,7 @@ abstract class AbstractWriter implements WriterInterface $source = substr($source, 6); list($zipFilename, $imageFilename) = explode('#', $source); - $zipClass = \PhpOffice\PhpWord\Settings::getZipClass(); - $zip = new $zipClass(); + $zip = new ZipArchive; if ($zip->open($zipFilename) !== false) { if ($zip->locateName($imageFilename)) { $zip->extractTo($this->getTempDir(), $imageFilename); @@ -347,7 +340,7 @@ abstract class AbstractWriter implements WriterInterface } if (!is_null($actualSource)) { - $objZip->addFile($actualSource, $target); + $zipPackage->addFile($actualSource, $target); } } diff --git a/src/PhpWord/Writer/HTML.php b/src/PhpWord/Writer/HTML.php index f871bc18..98cab55e 100644 --- a/src/PhpWord/Writer/HTML.php +++ b/src/PhpWord/Writer/HTML.php @@ -19,9 +19,10 @@ namespace PhpOffice\PhpWord\Writer; use PhpOffice\PhpWord\Exception\Exception; use PhpOffice\PhpWord\PhpWord; +use PhpOffice\PhpWord\Settings; +use PhpOffice\PhpWord\Style; use PhpOffice\PhpWord\Style\Font; use PhpOffice\PhpWord\Style\Paragraph; -use PhpOffice\PhpWord\Style; use PhpOffice\PhpWord\Writer\HTML\Element\Container; use PhpOffice\PhpWord\Writer\HTML\Element\TextRun as TextRunWriter; use PhpOffice\PhpWord\Writer\HTML\Style\Font as FontStyleWriter; @@ -62,14 +63,10 @@ class HTML extends AbstractWriter implements WriterInterface * Save PhpWord to file * * @param string $filename - * @throws Exception + * @throws \PhpOffice\PhpWord\Exception\Exception */ public function save($filename = null) { - if (is_null($this->phpWord)) { - throw new Exception('PhpWord object unassigned.'); - } - $this->setTempDir(sys_get_temp_dir() . '/PHPWordWriter/'); $hFile = fopen($filename, 'w'); if ($hFile !== false) { @@ -111,7 +108,8 @@ class HTML extends AbstractWriter implements WriterInterface */ private function writeHead() { - $properties = $this->getPhpWord()->getDocumentProperties(); + $phpWord = $this->getPhpWord(); + $properties = $phpWord->getDocumentProperties(); $propertiesMapping = array( 'creator' => 'author', 'title' => '', @@ -176,8 +174,8 @@ class HTML extends AbstractWriter implements WriterInterface // Default styles $defaultStyles = array( '*' => array( - 'font-family' => $this->getPhpWord()->getDefaultFontName(), - 'font-size' => $this->getPhpWord()->getDefaultFontSize() . 'pt', + 'font-family' => Settings::getDefaultFontName(), + 'font-size' => Settings::getDefaultFontSize() . 'pt', ), 'a.NoteRef' => array( 'text-decoration' => 'none', diff --git a/src/PhpWord/Writer/HTML/Element/AbstractElement.php b/src/PhpWord/Writer/HTML/Element/AbstractElement.php index 8da09414..53b994df 100644 --- a/src/PhpWord/Writer/HTML/Element/AbstractElement.php +++ b/src/PhpWord/Writer/HTML/Element/AbstractElement.php @@ -48,9 +48,16 @@ abstract class AbstractElement */ protected $withoutP = false; + /** + * Write element + */ + abstract public function write(); + /** * Create new instance * + * @param \PhpOffice\PhpWord\Writer\AbstractWriter $parentWriter + * @param \PhpOffice\PhpWord\Element\AbstractElement $element * @param bool $withoutP */ public function __construct(AbstractWriter $parentWriter, Element $element, $withoutP = false) diff --git a/src/PhpWord/Writer/HTML/Element/Container.php b/src/PhpWord/Writer/HTML/Element/Container.php index 6249426a..147329dd 100644 --- a/src/PhpWord/Writer/HTML/Element/Container.php +++ b/src/PhpWord/Writer/HTML/Element/Container.php @@ -17,6 +17,8 @@ namespace PhpOffice\PhpWord\Writer\HTML\Element; +use PhpOffice\PhpWord\Element\AbstractContainer as ContainerElement; + /** * Container element HTML writer * @@ -24,6 +26,13 @@ namespace PhpOffice\PhpWord\Writer\HTML\Element; */ class Container extends AbstractElement { + /** + * Namespace; Can't use __NAMESPACE__ in inherited class (RTF) + * + * @var string + */ + protected $namespace = 'PhpOffice\\PhpWord\\Writer\\HTML\\Element'; + /** * Write container * @@ -32,14 +41,19 @@ class Container extends AbstractElement public function write() { $container = $this->element; + if (!$container instanceof ContainerElement) { + return ''; + } $containerClass = substr(get_class($container), strrpos(get_class($container), '\\') + 1); $withoutP = in_array($containerClass, array('TextRun', 'Footnote', 'Endnote')) ? true : false; $content = ''; $elements = $container->getElements(); foreach ($elements as $element) { - $writerClass = str_replace('\\Element', '\\Writer\\HTML\\Element', get_class($element)); + $elementClass = get_class($element); + $writerClass = str_replace('PhpOffice\\PhpWord\\Element', $this->namespace, $elementClass); if (class_exists($writerClass)) { + /** @var \PhpOffice\PhpWord\Writer\HTML\Element\AbstractElement $writer Type hint */ $writer = new $writerClass($this->parentWriter, $element, $withoutP); $content .= $writer->write(); } diff --git a/src/PhpWord/Writer/HTML/Element/Footnote.php b/src/PhpWord/Writer/HTML/Element/Footnote.php index cd1baacb..f59545de 100644 --- a/src/PhpWord/Writer/HTML/Element/Footnote.php +++ b/src/PhpWord/Writer/HTML/Element/Footnote.php @@ -38,11 +38,17 @@ class Footnote extends AbstractElement */ public function write() { - $noteId = count($this->parentWriter->getNotes()) + 1; + if (!$this->element instanceof \PhpOffice\PhpWord\Element\Footnote) { + return ''; + } + /** @var \PhpOffice\PhpWord\Writer\HTML $parentWriter Type hint */ + $parentWriter = $this->parentWriter; + + $noteId = count($parentWriter->getNotes()) + 1; $noteMark = $this->noteType . '-' . $this->element->getRelationId(); $content = "{$noteId}"; - $this->parentWriter->addNote($noteId, $noteMark); + $parentWriter->addNote($noteId, $noteMark); return $content; } diff --git a/src/PhpWord/Writer/HTML/Element/Image.php b/src/PhpWord/Writer/HTML/Element/Image.php index 2ae87865..dafc1c38 100644 --- a/src/PhpWord/Writer/HTML/Element/Image.php +++ b/src/PhpWord/Writer/HTML/Element/Image.php @@ -18,6 +18,7 @@ namespace PhpOffice\PhpWord\Writer\HTML\Element; use PhpOffice\PhpWord\Element\Image as ImageElement; +use PhpOffice\PhpWord\Shared\ZipArchive; use PhpOffice\PhpWord\Writer\HTML\Style\Image as ImageStyleWriter; /** @@ -34,8 +35,14 @@ class Image extends Text */ public function write() { + if (!$this->element instanceof ImageElement) { + return ''; + } + /** @var \PhpOffice\PhpWord\Writer\HTML $parentWriter Type hint */ + $parentWriter = $this->parentWriter; + $content = ''; - if (!$this->parentWriter->isPdf()) { + if (!$parentWriter->isPdf()) { $imageData = $this->getBase64ImageData($this->element); if (!is_null($imageData)) { $styleWriter = new ImageStyleWriter($this->element->getStyle()); @@ -53,6 +60,7 @@ class Image extends Text /** * Get Base64 image data * + * @param \PhpOffice\PhpWord\Element\Image $element * @return string|null */ private function getBase64ImageData(ImageElement $element) @@ -69,8 +77,7 @@ class Image extends Text $source = substr($source, 6); list($zipFilename, $imageFilename) = explode('#', $source); - $zipClass = \PhpOffice\PhpWord\Settings::getZipClass(); - $zip = new $zipClass(); + $zip = new ZipArchive(); if ($zip->open($zipFilename) !== false) { if ($zip->locateName($imageFilename)) { $zip->extractTo($this->parentWriter->getTempDir(), $imageFilename); diff --git a/src/PhpWord/Writer/HTML/Element/Link.php b/src/PhpWord/Writer/HTML/Element/Link.php index 6f1977f8..d1256eb0 100644 --- a/src/PhpWord/Writer/HTML/Element/Link.php +++ b/src/PhpWord/Writer/HTML/Element/Link.php @@ -31,6 +31,10 @@ class Link extends Text */ public function write() { + if (!$this->element instanceof \PhpOffice\PhpWord\Element\Link) { + return ''; + } + $content = ''; $content .= $this->writeOpening(); $content .= "element->getTarget()}\">{$this->element->getText()}"; diff --git a/src/PhpWord/Writer/HTML/Element/ListItem.php b/src/PhpWord/Writer/HTML/Element/ListItem.php index 722d920a..79a3b393 100644 --- a/src/PhpWord/Writer/HTML/Element/ListItem.php +++ b/src/PhpWord/Writer/HTML/Element/ListItem.php @@ -31,6 +31,10 @@ class ListItem extends AbstractElement */ public function write() { + if (!$this->element instanceof \PhpOffice\PhpWord\Element\ListItem) { + return ''; + } + $text = htmlspecialchars($this->element->getTextObject()->getText()); $content = '

' . $text . '

' . PHP_EOL; diff --git a/src/PhpWord/Writer/HTML/Element/Table.php b/src/PhpWord/Writer/HTML/Element/Table.php index a92deea6..c8813a67 100644 --- a/src/PhpWord/Writer/HTML/Element/Table.php +++ b/src/PhpWord/Writer/HTML/Element/Table.php @@ -31,15 +31,20 @@ class Table extends AbstractElement */ public function write() { + if (!$this->element instanceof \PhpOffice\PhpWord\Element\Table) { + return ''; + } + $content = ''; $rows = $this->element->getRows(); $rowCount = count($rows); if ($rowCount > 0) { $content .= '' . PHP_EOL; foreach ($rows as $row) { - // $height = $row->getHeight(); + /** @var $row \PhpOffice\PhpWord\Element\Row Type hint */ $rowStyle = $row->getStyle(); - $tblHeader = $rowStyle->getTblHeader(); + // $height = $row->getHeight(); + $tblHeader = $rowStyle->isTblHeader(); $content .= '' . PHP_EOL; foreach ($row->getCells() as $cell) { $writer = new Container($this->parentWriter, $cell); diff --git a/src/PhpWord/Writer/HTML/Element/Text.php b/src/PhpWord/Writer/HTML/Element/Text.php index 883a8cd3..cbabc645 100644 --- a/src/PhpWord/Writer/HTML/Element/Text.php +++ b/src/PhpWord/Writer/HTML/Element/Text.php @@ -53,7 +53,7 @@ class Text extends AbstractElement /** * Closing tag * - * @var strings + * @var string */ private $closingTags = ''; @@ -64,12 +64,14 @@ class Text extends AbstractElement */ public function write() { + /** @var \PhpOffice\PhpWord\Element\Text $element Type hint */ + $element = $this->element; $this->getFontStyle(); $content = ''; $content .= $this->writeOpening(); $content .= $this->openingTags; - $content .= htmlspecialchars($this->element->getText()); + $content .= htmlspecialchars($element->getText()); $content .= $this->closingTags; $content .= $this->closingText; $content .= $this->writeClosing(); @@ -140,12 +142,14 @@ class Text extends AbstractElement */ private function getParagraphStyle() { + /** @var \PhpOffice\PhpWord\Element\Text $element Type hint */ + $element = $this->element; $style = ''; - if (method_exists($this->element, 'getParagraphStyle')) { + if (!method_exists($element, 'getParagraphStyle')) { return $style; } - $paragraphStyle = $this->element->getParagraphStyle(); + $paragraphStyle = $element->getParagraphStyle(); $pStyleIsObject = ($paragraphStyle instanceof Paragraph); if ($pStyleIsObject) { $styleWriter = new ParagraphStyleWriter($paragraphStyle); @@ -164,8 +168,10 @@ class Text extends AbstractElement */ private function getFontStyle() { + /** @var \PhpOffice\PhpWord\Element\Text $element Type hint */ + $element = $this->element; $style = ''; - $fontStyle = $this->element->getFontStyle(); + $fontStyle = $element->getFontStyle(); $fStyleIsObject = ($fontStyle instanceof Font); if ($fStyleIsObject) { $styleWriter = new FontStyleWriter($fontStyle); diff --git a/src/PhpWord/Writer/HTML/Element/Title.php b/src/PhpWord/Writer/HTML/Element/Title.php index 2a33a282..20747bf9 100644 --- a/src/PhpWord/Writer/HTML/Element/Title.php +++ b/src/PhpWord/Writer/HTML/Element/Title.php @@ -31,6 +31,10 @@ class Title extends AbstractElement */ public function write() { + if (!$this->element instanceof \PhpOffice\PhpWord\Element\Title) { + return ''; + } + $tag = 'h' . $this->element->getDepth(); $text = htmlspecialchars($this->element->getText()); $content = "<{$tag}>{$text}" . PHP_EOL; diff --git a/src/PhpWord/Writer/HTML/Style/AbstractStyle.php b/src/PhpWord/Writer/HTML/Style/AbstractStyle.php index d25e7b6a..cd37174a 100644 --- a/src/PhpWord/Writer/HTML/Style/AbstractStyle.php +++ b/src/PhpWord/Writer/HTML/Style/AbstractStyle.php @@ -56,7 +56,7 @@ abstract class AbstractStyle public function getStyle() { if (!$this->style instanceof Style && !is_array($this->style)) { - return; + return ''; } return $this->style; @@ -87,12 +87,12 @@ abstract class AbstractStyle /** * Get value if ... * - * @param bool $condition + * @param bool|null $condition * @param string $value * @return string */ protected function getValueIf($condition, $value) { - return $condition ? $value : ''; + return $condition == true ? $value : ''; } } diff --git a/src/PhpWord/Writer/HTML/Style/Font.php b/src/PhpWord/Writer/HTML/Style/Font.php index 33c23f7a..aec36bbb 100644 --- a/src/PhpWord/Writer/HTML/Style/Font.php +++ b/src/PhpWord/Writer/HTML/Style/Font.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWord\Writer\HTML\Style; -use PhpOffice\PhpWord\PhpWord; +use PhpOffice\PhpWord\Settings; use PhpOffice\PhpWord\Style\Font as FontStyle; /** @@ -35,8 +35,8 @@ class Font extends AbstractStyle public function write() { $style = $this->getStyle(); - if (!$style instanceof \PhpOffice\PhpWord\Style\Font) { - return; + if (!$style instanceof FontStyle) { + return ''; } $css = array(); @@ -47,9 +47,9 @@ class Font extends AbstractStyle $underline = $style->getUnderline() != FontStyle::UNDERLINE_NONE; $lineThrough = $style->isStrikethrough() || $style->isDoubleStrikethrough(); - $css['font-family'] = $this->getValueIf($font != PhpWord::DEFAULT_FONT_NAME, "'{$font}'"); - $css['font-size'] = $this->getValueIf($size != PhpWord::DEFAULT_FONT_SIZE, "{$size}pt"); - $css['color'] = $this->getValueIf($color != PhpWord::DEFAULT_FONT_COLOR, "#{$color}"); + $css['font-family'] = $this->getValueIf($font !== null, "'{$font}'"); + $css['font-size'] = $this->getValueIf($size !== null, "{$size}pt"); + $css['color'] = $this->getValueIf($color != Settings::DEFAULT_FONT_COLOR, "#{$color}"); $css['background'] = $this->getValueIf($fgColor != '', $fgColor); $css['font-weight'] = $this->getValueIf($style->isBold(), 'bold'); $css['font-style'] = $this->getValueIf($style->isItalic(), 'italic'); diff --git a/src/PhpWord/Writer/HTML/Style/Image.php b/src/PhpWord/Writer/HTML/Style/Image.php index fcf18395..13be3665 100644 --- a/src/PhpWord/Writer/HTML/Style/Image.php +++ b/src/PhpWord/Writer/HTML/Style/Image.php @@ -33,12 +33,14 @@ class Image extends AbstractStyle { $style = $this->getStyle(); if (!$style instanceof \PhpOffice\PhpWord\Style\Image) { - return; + return ''; } $css = array(); - $css['width'] = $this->getValueIf($style->getWidth(), $style->getWidth() . 'px'); - $css['height'] = $this->getValueIf($style->getHeight(), $style->getHeight() . 'px'); + $width = $style->getWidth(); + $height = $style->getHeight(); + $css['width'] = $this->getValueIf(is_numeric($width), $width . 'px'); + $css['height'] = $this->getValueIf(is_numeric($height), $height . 'px'); return $this->assembleCss($css); } diff --git a/src/PhpWord/Writer/HTML/Style/Paragraph.php b/src/PhpWord/Writer/HTML/Style/Paragraph.php index cc3ad785..8b326a5c 100644 --- a/src/PhpWord/Writer/HTML/Style/Paragraph.php +++ b/src/PhpWord/Writer/HTML/Style/Paragraph.php @@ -17,8 +17,6 @@ namespace PhpOffice\PhpWord\Writer\HTML\Style; -use PhpOffice\PhpWord\Settings; - /** * Paragraph style HTML writer * @@ -35,7 +33,7 @@ class Paragraph extends AbstractStyle { $style = $this->getStyle(); if (!$style instanceof \PhpOffice\PhpWord\Style\Paragraph) { - return; + return ''; } $css = array(); @@ -48,8 +46,8 @@ class Paragraph extends AbstractStyle if (!is_null($spacing)) { $before = $spacing->getBefore(); $after = $spacing->getAfter(); - $css['margin-top'] = $this->getValueIf(!is_null($before), ($before / Settings::UNIT_POINT) . 'pt'); - $css['margin-bottom'] = $this->getValueIf(!is_null($after), ($after / Settings::UNIT_POINT) . 'pt'); + $css['margin-top'] = $this->getValueIf(!is_null($before), ($before / 20) . 'pt'); + $css['margin-bottom'] = $this->getValueIf(!is_null($after), ($after / 20) . 'pt'); } return $this->assembleCss($css); diff --git a/src/PhpWord/Writer/ODText.php b/src/PhpWord/Writer/ODText.php index 72c4a0b5..f9c8d5d4 100644 --- a/src/PhpWord/Writer/ODText.php +++ b/src/PhpWord/Writer/ODText.php @@ -17,7 +17,6 @@ namespace PhpOffice\PhpWord\Writer; -use PhpOffice\PhpWord\Exception\Exception; use PhpOffice\PhpWord\Media; use PhpOffice\PhpWord\PhpWord; @@ -49,6 +48,7 @@ class ODText extends AbstractWriter implements WriterInterface foreach (array_keys($this->parts) as $partName) { $partClass = get_class($this) . '\\Part\\' . $partName; if (class_exists($partClass)) { + /** @var $partObject \PhpOffice\PhpWord\Writer\ODText\Part\AbstractPart Type hint */ $partObject = new $partClass(); $partObject->setParentWriter($this); $this->writerParts[strtolower($partName)] = $partObject; @@ -63,35 +63,27 @@ class ODText extends AbstractWriter implements WriterInterface * Save PhpWord to file * * @param string $filename - * @throws \PhpOffice\PhpWord\Exception\Exception */ public function save($filename = null) { - if (is_null($this->phpWord)) { - throw new Exception('PhpWord object unassigned.'); - } - $filename = $this->getTempFile($filename); - $objZip = $this->getZipArchive($filename); + $zip = $this->getZipArchive($filename); // Add section media files $sectionMedia = Media::getElements('section'); if (!empty($sectionMedia)) { - $this->addFilesToPackage($objZip, $sectionMedia); + $this->addFilesToPackage($zip, $sectionMedia); } // Write parts foreach ($this->parts as $partName => $fileName) { if ($fileName != '') { - $objZip->addFromString($fileName, $this->getWriterPart($partName)->write()); + $zip->addFromString($fileName, $this->getWriterPart($partName)->write()); } } - // Close file - if ($objZip->close() === false) { - throw new Exception("Could not close zip file $filename."); - } - + // Close zip archive and cleanup temp file + $zip->close(); $this->cleanupTempFile(); } } diff --git a/src/PhpWord/Writer/ODText/Element/AbstractElement.php b/src/PhpWord/Writer/ODText/Element/AbstractElement.php index 42f86af4..9fb24364 100644 --- a/src/PhpWord/Writer/ODText/Element/AbstractElement.php +++ b/src/PhpWord/Writer/ODText/Element/AbstractElement.php @@ -17,11 +17,13 @@ namespace PhpOffice\PhpWord\Writer\ODText\Element; +use PhpOffice\PhpWord\Writer\Word2007\Element\AbstractElement as Word2007AbstractElement; + /** * Abstract element writer * * @since 0.11.0 */ -abstract class AbstractElement extends \PhpOffice\PhpWord\Writer\Word2007\Element\AbstractElement +abstract class AbstractElement extends Word2007AbstractElement { } diff --git a/src/PhpWord/Writer/ODText/Element/Container.php b/src/PhpWord/Writer/ODText/Element/Container.php index 30517bb9..8b7807d6 100644 --- a/src/PhpWord/Writer/ODText/Element/Container.php +++ b/src/PhpWord/Writer/ODText/Element/Container.php @@ -17,12 +17,14 @@ namespace PhpOffice\PhpWord\Writer\ODText\Element; +use PhpOffice\PhpWord\Writer\Word2007\Element\Container as Word2007Container; + /** * Container element writer (section, textrun, header, footnote, cell, etc.) * * @since 0.11.0 */ -class Container extends \PhpOffice\PhpWord\Writer\Word2007\Element\Container +class Container extends Word2007Container { /** * Namespace; Can't use __NAMESPACE__ in inherited class (ODText) diff --git a/src/PhpWord/Writer/ODText/Element/Image.php b/src/PhpWord/Writer/ODText/Element/Image.php index 909a9aed..3229b59c 100644 --- a/src/PhpWord/Writer/ODText/Element/Image.php +++ b/src/PhpWord/Writer/ODText/Element/Image.php @@ -33,6 +33,9 @@ class Image extends AbstractElement { $xmlWriter = $this->getXmlWriter(); $element = $this->getElement(); + if (!$element instanceof \PhpOffice\PhpWord\Element\Image) { + return; + } $mediaIndex = $element->getMediaIndex(); $target = 'Pictures/' . $element->getTarget(); diff --git a/src/PhpWord/Writer/ODText/Element/Link.php b/src/PhpWord/Writer/ODText/Element/Link.php index 1ccac435..79d3aa24 100644 --- a/src/PhpWord/Writer/ODText/Element/Link.php +++ b/src/PhpWord/Writer/ODText/Element/Link.php @@ -31,6 +31,9 @@ class Link extends AbstractElement { $xmlWriter = $this->getXmlWriter(); $element = $this->getElement(); + if (!$element instanceof \PhpOffice\PhpWord\Element\Link) { + return; + } if (!$this->withoutP) { $xmlWriter->startElement('text:p'); // text:p diff --git a/src/PhpWord/Writer/ODText/Element/Table.php b/src/PhpWord/Writer/ODText/Element/Table.php index 411f1f38..f26960b8 100644 --- a/src/PhpWord/Writer/ODText/Element/Table.php +++ b/src/PhpWord/Writer/ODText/Element/Table.php @@ -31,6 +31,9 @@ class Table extends AbstractElement { $xmlWriter = $this->getXmlWriter(); $element = $this->getElement(); + if (!$element instanceof \PhpOffice\PhpWord\Element\Table) { + return; + } $rows = $element->getRows(); $rowCount = count($rows); $colCount = $element->countColumns(); @@ -46,6 +49,7 @@ class Table extends AbstractElement foreach ($rows as $row) { $xmlWriter->startElement('table:table-row'); + /** @var $row \PhpOffice\PhpWord\Element\Row Type hint */ foreach ($row->getCells() as $cell) { $xmlWriter->startElement('table:table-cell'); $xmlWriter->writeAttribute('office:value-type', 'string'); diff --git a/src/PhpWord/Writer/ODText/Element/Text.php b/src/PhpWord/Writer/ODText/Element/Text.php index e960dea8..4fc53bfe 100644 --- a/src/PhpWord/Writer/ODText/Element/Text.php +++ b/src/PhpWord/Writer/ODText/Element/Text.php @@ -17,6 +17,8 @@ namespace PhpOffice\PhpWord\Writer\ODText\Element; +use PhpOffice\PhpWord\Exception\Exception; + /** * Text element writer * @@ -31,6 +33,9 @@ class Text extends AbstractElement { $xmlWriter = $this->getXmlWriter(); $element = $this->getElement(); + if (!$element instanceof \PhpOffice\PhpWord\Element\Text) { + return; + } $fontStyle = $element->getFontStyle(); $paragraphStyle = $element->getParagraphStyle(); diff --git a/src/PhpWord/Writer/ODText/Element/Title.php b/src/PhpWord/Writer/ODText/Element/Title.php new file mode 100644 index 00000000..d45f5e12 --- /dev/null +++ b/src/PhpWord/Writer/ODText/Element/Title.php @@ -0,0 +1,43 @@ +getXmlWriter(); + $element = $this->getElement(); + if (!$element instanceof \PhpOffice\PhpWord\Element\Title) { + return; + } + + $xmlWriter->startElement('text:h'); + $xmlWriter->writeAttribute('text:outline-level', $element->getDepth()); + $xmlWriter->writeRaw($element->getText()); + $xmlWriter->endElement(); // text:h + } +} diff --git a/src/PhpWord/Writer/ODText/Part/AbstractPart.php b/src/PhpWord/Writer/ODText/Part/AbstractPart.php index c5a3b0c6..d5397ffd 100644 --- a/src/PhpWord/Writer/ODText/Part/AbstractPart.php +++ b/src/PhpWord/Writer/ODText/Part/AbstractPart.php @@ -17,15 +17,16 @@ namespace PhpOffice\PhpWord\Writer\ODText\Part; -use PhpOffice\PhpWord\PhpWord; +use PhpOffice\PhpWord\Settings; use PhpOffice\PhpWord\Shared\XMLWriter; -use PhpOffice\PhpWord\Style\Font; use PhpOffice\PhpWord\Style; +use PhpOffice\PhpWord\Style\Font; +use PhpOffice\PhpWord\Writer\Word2007\Part\AbstractPart as Word2007AbstractPart; /** * ODText writer part abstract */ -abstract class AbstractPart extends \PhpOffice\PhpWord\Writer\Word2007\Part\AbstractPart +abstract class AbstractPart extends Word2007AbstractPart { /** * Write common root attributes @@ -67,7 +68,7 @@ abstract class AbstractPart extends \PhpOffice\PhpWord\Writer\Word2007\Part\Abst protected function writeFontFaces(XMLWriter $xmlWriter) { $xmlWriter->startElement('office:font-face-decls'); - $arrFonts = array(); + $fontTable = array(); $styles = Style::getStyles(); $numFonts = 0; if (count($styles) > 0) { @@ -76,8 +77,8 @@ abstract class AbstractPart extends \PhpOffice\PhpWord\Writer\Word2007\Part\Abst if ($style instanceof Font) { $numFonts++; $name = $style->getName(); - if (!in_array($name, $arrFonts)) { - $arrFonts[] = $name; + if (!in_array($name, $fontTable)) { + $fontTable[] = $name; // style:font-face $xmlWriter->startElement('style:font-face'); @@ -88,10 +89,10 @@ abstract class AbstractPart extends \PhpOffice\PhpWord\Writer\Word2007\Part\Abst } } } - if (!in_array(PhpWord::DEFAULT_FONT_NAME, $arrFonts)) { + if (!in_array(Settings::getDefaultFontName(), $fontTable)) { $xmlWriter->startElement('style:font-face'); - $xmlWriter->writeAttribute('style:name', PhpWord::DEFAULT_FONT_NAME); - $xmlWriter->writeAttribute('svg:font-family', PhpWord::DEFAULT_FONT_NAME); + $xmlWriter->writeAttribute('style:name', Settings::getDefaultFontName()); + $xmlWriter->writeAttribute('svg:font-family', Settings::getDefaultFontName()); $xmlWriter->endElement(); } $xmlWriter->endElement(); diff --git a/src/PhpWord/Writer/ODText/Part/Content.php b/src/PhpWord/Writer/ODText/Part/Content.php index f5ae1883..900edfdd 100644 --- a/src/PhpWord/Writer/ODText/Part/Content.php +++ b/src/PhpWord/Writer/ODText/Part/Content.php @@ -17,21 +17,34 @@ namespace PhpOffice\PhpWord\Writer\ODText\Part; +use PhpOffice\PhpWord\Element\Image; use PhpOffice\PhpWord\Element\Table; use PhpOffice\PhpWord\Element\Text; -use PhpOffice\PhpWord\Media; +use PhpOffice\PhpWord\Element\TextRun; use PhpOffice\PhpWord\PhpWord; use PhpOffice\PhpWord\Shared\XMLWriter; +use PhpOffice\PhpWord\Style; use PhpOffice\PhpWord\Style\Font; use PhpOffice\PhpWord\Style\Paragraph; -use PhpOffice\PhpWord\Style; +use PhpOffice\PhpWord\Style\Table as TableStyle; use PhpOffice\PhpWord\Writer\ODText\Element\Container; +use PhpOffice\PhpWord\Writer\ODText\Style\Paragraph as ParagraphStyleWriter; /** * ODText content part writer: content.xml */ class Content extends AbstractPart { + /** + * Auto style collection + * + * Collect inline style information from section, image, and table elements + * + * @todo Merge font and paragraph styles + * @var array + */ + private $autoStyles = array('Section' => array(), 'Image' => array(), 'Table' => array()); + /** * Write part * @@ -39,8 +52,10 @@ class Content extends AbstractPart */ public function write() { - $phpWord = $this->getParentWriter()->getPhpWord(); $xmlWriter = $this->getXmlWriter(); + $phpWord = $this->getParentWriter()->getPhpWord(); + + $this->getAutoStyles($phpWord); $xmlWriter->startDocument('1.0', 'UTF-8'); $xmlWriter->startElement('office:document-content'); @@ -51,14 +66,15 @@ class Content extends AbstractPart $xmlWriter->writeAttribute('xmlns:field', 'urn:openoffice:names:experimental:ooo-ms-interop:xmlns:field:1.0'); $xmlWriter->writeAttribute('xmlns:formx', 'urn:openoffice:names:experimental:ooxml-odf-interop:xmlns:form:1.0'); - $this->getAutomaticStyles($phpWord); + // Font declarations and automatic styles $this->writeFontFaces($xmlWriter); // office:font-face-decls - $this->writeAutomaticStyles($xmlWriter, $phpWord); // office:automatic-styles + $this->writeAutoStyles($xmlWriter); // office:automatic-styles + // Body $xmlWriter->startElement('office:body'); $xmlWriter->startElement('office:text'); - // text:sequence-decls + // Sequence declarations $sequences = array('Illustration', 'Table', 'Text', 'Drawing'); $xmlWriter->startElement('text:sequence-decls'); foreach ($sequences as $sequence) { @@ -69,42 +85,61 @@ class Content extends AbstractPart } $xmlWriter->endElement(); // text:sequence-decl + // Sections $sections = $phpWord->getSections(); - $sectionCount = count($sections); - if ($sectionCount > 0) { - foreach ($sections as $section) { - // $xmlWriter->startElement('text:section'); - $containerWriter = new Container($xmlWriter, $section); - $containerWriter->write(); - // $xmlWriter->endElement(); // text:section - } + foreach ($sections as $section) { + $name = 'Section' . $section->getSectionId(); + $xmlWriter->startElement('text:section'); + $xmlWriter->writeAttribute('text:name', $name); + $xmlWriter->writeAttribute('text:style-name', $name); + $containerWriter = new Container($xmlWriter, $section); + $containerWriter->write(); + $xmlWriter->endElement(); // text:section } + $xmlWriter->endElement(); // office:text $xmlWriter->endElement(); // office:body + $xmlWriter->endElement(); // office:document-content return $xmlWriter->getData(); } /** - * Write automatic styles + * Write automatic styles other than fonts and paragraphs + * + * @since 0.11.0 */ - private function writeAutomaticStyles(XMLWriter $xmlWriter, PhpWord $phpWord) + private function writeAutoStyles(XMLWriter $xmlWriter) { $xmlWriter->startElement('office:automatic-styles'); - // Font and paragraph + $this->writeTextStyles($xmlWriter); + foreach ($this->autoStyles as $element => $style) { + $writerClass = 'PhpOffice\\PhpWord\\Writer\\ODText\\Style\\' . $element; + + /** @var \PhpOffice\PhpWord\Writer\ODText\Style\AbstractStyle $styleWriter Type hint */ + $styleWriter = new $writerClass($xmlWriter, $style); + $styleWriter->write(); + } + + $xmlWriter->endElement(); // office:automatic-styles + } + + /** + * Write automatic styles + */ + private function writeTextStyles(XMLWriter $xmlWriter) + { $styles = Style::getStyles(); $paragraphStyleCount = 0; if (count($styles) > 0) { - foreach ($styles as $styleName => $style) { - if (preg_match('#^T[0-9]+$#', $styleName) != 0 - || preg_match('#^P[0-9]+$#', $styleName) != 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->setIsAuto(true); $styleWriter->write(); } if ($style instanceof Paragraph) { @@ -115,92 +150,90 @@ class Content extends AbstractPart if ($paragraphStyleCount == 0) { $style = new Paragraph(); $style->setStyleName('P1'); - $styleWriter = new \PhpOffice\PhpWord\Writer\ODText\Style\Paragraph($xmlWriter, $style); - $styleWriter->setIsAuto(true); + $style->setAuto(); + $styleWriter = new ParagraphStyleWriter($xmlWriter, $style); $styleWriter->write(); } } - - // Images - $images = Media::getElements('section'); - foreach ($images as $image) { - if ($image['type'] == 'image') { - $xmlWriter->startElement('style:style'); - $xmlWriter->writeAttribute('style:name', 'fr' . $image['rID']); - $xmlWriter->writeAttribute('style:family', 'graphic'); - $xmlWriter->writeAttribute('style:parent-style-name', 'Graphics'); - $xmlWriter->startElement('style:graphic-properties'); - $xmlWriter->writeAttribute('style:vertical-pos', 'top'); - $xmlWriter->writeAttribute('style:vertical-rel', 'baseline'); - $xmlWriter->endElement(); - $xmlWriter->endElement(); - } - } - - // Tables - $sections = $phpWord->getSections(); - $sectionCount = count($sections); - if ($sectionCount > 0) { - $sectionId = 0; - foreach ($sections as $section) { - $sectionId++; - $elements = $section->getElements(); - foreach ($elements as $element) { - if ($elements instanceof Table) { - $xmlWriter->startElement('style:style'); - $xmlWriter->writeAttribute('style:name', $element->getElementId()); - $xmlWriter->writeAttribute('style:family', 'table'); - $xmlWriter->startElement('style:table-properties'); - //$xmlWriter->writeAttribute('style:width', 'table'); - $xmlWriter->writeAttribute('style:rel-width', 100); - $xmlWriter->writeAttribute('table:align', 'center'); - $xmlWriter->endElement(); - $xmlWriter->endElement(); - } - } - } - } - - $xmlWriter->endElement(); // office:automatic-styles } /** - * Set automatic styles + * Get automatic styles */ - private function getAutomaticStyles(PhpWord $phpWord) + private function getAutoStyles(PhpWord $phpWord) { $sections = $phpWord->getSections(); - $sectionCount = count($sections); - if ($sectionCount > 0) { - $paragraphStyleCount = 0; - $fontStyleCount = 0; - foreach ($sections as $section) { - $elements = $section->getElements(); - foreach ($elements as $element) { - if ($element instanceof Text) { - $fontStyle = $element->getFontStyle(); - $paragraphStyle = $element->getParagraphStyle(); + $paragraphStyleCount = 0; + $fontStyleCount = 0; + foreach ($sections as $section) { + $style = $section->getSettings(); + $style->setStyleName("Section{$section->getSectionId()}"); + $this->autoStyles['Section'][] = $style; + $this->getContainerStyle($section, $paragraphStyleCount, $fontStyleCount); + } + } - // Font - if ($fontStyle instanceof Font) { - $fontStyleCount++; - $arrStyle = array( - 'color' => $fontStyle->getColor(), - 'name' => $fontStyle->getName() - ); - $phpWord->addFontStyle('T' . $fontStyleCount, $arrStyle); - $element->setFontStyle('T' . $fontStyleCount); - - // Paragraph - } elseif ($paragraphStyle instanceof Paragraph) { - $paragraphStyleCount++; - - $phpWord->addParagraphStyle('P' . $paragraphStyleCount, array()); - $element->setParagraphStyle('P' . $paragraphStyleCount); - } - } + /** + * Get all styles of each elements in container recursively + * + * Table style can be null or string of the style name + * + * @param \PhpOffice\PhpWord\Element\AbstractContainer $container + * @param int $paragraphStyleCount + * @param int $fontStyleCount + * @todo Simplify the logic + */ + private function getContainerStyle($container, &$paragraphStyleCount, &$fontStyleCount) + { + $elements = $container->getElements(); + foreach ($elements as $element) { + if ($element instanceof TextRun) { + $this->getContainerStyle($element, $paragraphStyleCount, $fontStyleCount); + } elseif ($element instanceof Text) { + $this->getElementStyle($element, $paragraphStyleCount, $fontStyleCount); + } elseif ($element instanceof Image) { + $style = $element->getStyle(); + $style->setStyleName('fr' . $element->getMediaIndex()); + $this->autoStyles['Image'][] = $style; + } elseif ($element instanceof Table) { + $style = $element->getStyle(); + if ($style === null) { + $style = new TableStyle(); + } elseif (is_string($style)) { + $style = Style::getStyle($style); } + $style->setStyleName($element->getElementId()); + $this->autoStyles['Table'][] = $style; } } } + + /** + * Get style of individual element + * + * @param \PhpOffice\PhpWord\Element\Text $element + * @param int $paragraphStyleCount + * @param int $fontStyleCount + */ + private function getElementStyle(&$element, &$paragraphStyleCount, &$fontStyleCount) + { + $fontStyle = $element->getFontStyle(); + $paragraphStyle = $element->getParagraphStyle(); + $phpWord = $this->getParentWriter()->getPhpWord(); + + // Font + if ($fontStyle instanceof Font) { + $fontStyleCount++; + $style = $phpWord->addFontStyle("T{$fontStyleCount}", $fontStyle); + $style->setAuto(); + $element->setFontStyle("T{$fontStyleCount}"); + + // Paragraph + } elseif ($paragraphStyle instanceof Paragraph) { + $paragraphStyleCount++; + $style = $phpWord->addParagraphStyle("P{$paragraphStyleCount}", array()); + $style->setAuto(); + $element->setParagraphStyle("P{$paragraphStyleCount}"); + } + } } diff --git a/src/PhpWord/Writer/ODText/Part/Meta.php b/src/PhpWord/Writer/ODText/Part/Meta.php index 6ed58213..50a38047 100644 --- a/src/PhpWord/Writer/ODText/Part/Meta.php +++ b/src/PhpWord/Writer/ODText/Part/Meta.php @@ -17,10 +17,12 @@ namespace PhpOffice\PhpWord\Writer\ODText\Part; -use PhpOffice\PhpWord\PhpWord; +use PhpOffice\PhpWord\Shared\XMLWriter; /** * ODText meta part writer: meta.xml + * + * @since 0.11.0 */ class Meta extends AbstractPart { @@ -44,27 +46,61 @@ class Meta extends AbstractPart $xmlWriter->writeAttribute('xmlns:meta', 'urn:oasis:names:tc:opendocument:xmlns:meta:1.0'); $xmlWriter->writeAttribute('xmlns:ooo', 'http://openoffice.org/2004/office'); $xmlWriter->writeAttribute('xmlns:grddl', 'http://www.w3.org/2003/g/data-view#'); - - // office:meta $xmlWriter->startElement('office:meta'); + + // Core properties + $xmlWriter->writeElement('dc:title', $docProps->getTitle()); + $xmlWriter->writeElement('dc:subject', $docProps->getSubject()); + $xmlWriter->writeElement('dc:description', $docProps->getDescription()); $xmlWriter->writeElement('dc:creator', $docProps->getLastModifiedBy()); $xmlWriter->writeElement('dc:date', gmdate('Y-m-d\TH:i:s.000', $docProps->getModified())); - $xmlWriter->writeElement('dc:description', $docProps->getDescription()); - $xmlWriter->writeElement('dc:subject', $docProps->getSubject()); - $xmlWriter->writeElement('dc:title', $docProps->getTitle()); - $xmlWriter->writeElement('meta:creation-date', gmdate('Y-m-d\TH:i:s.000', $docProps->getCreated())); + + // Extended properties + $xmlWriter->writeElement('meta:generator', 'PHPWord'); $xmlWriter->writeElement('meta:initial-creator', $docProps->getCreator()); + $xmlWriter->writeElement('meta:creation-date', gmdate('Y-m-d\TH:i:s.000', $docProps->getCreated())); $xmlWriter->writeElement('meta:keyword', $docProps->getKeywords()); - // @todo : Where these properties are written ? - // $docProps->getCategory() - // $docProps->getCompany() + // Category, company, and manager are put in meta namespace + $properties = array('Category', 'Company', 'Manager'); + foreach ($properties as $property) { + $method = "get{$property}"; + if ($docProps->$method() !== null) { + $this->writeCustomProperty($xmlWriter, $property, $docProps->$method()); + } + } - $xmlWriter->endElement(); + // Other custom properties + // @todo Check type. Currently all assumed as string + foreach ($docProps->getCustomProperties() as $property) { + $value = $docProps->getCustomPropertyValue($property); + $this->writeCustomProperty($xmlWriter, $property, $value); + } - $xmlWriter->endElement(); + $xmlWriter->endElement(); // office:meta + $xmlWriter->endElement(); // office:document-meta - // Return return $xmlWriter->getData(); } + + /** + * Write individual property + * + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @param string $property + * @param string $value + * @param string $type string (default/null) + * + * @todo Handle other `$type`: double|date|dateTime|duration|boolean + */ + private function writeCustomProperty(XMLWriter $xmlWriter, $property, $value, $type = null) + { + $xmlWriter->startElement('meta:user-defined'); + $xmlWriter->writeAttribute('meta:name', $property); + if ($type !== null) { + $xmlWriter->writeAttribute('meta:value-type', $type); + } + $xmlWriter->writeRaw($value); + $xmlWriter->endElement(); // meta:user-defined + } } diff --git a/src/PhpWord/Writer/ODText/Part/Styles.php b/src/PhpWord/Writer/ODText/Part/Styles.php index 7641d94f..b7864fe3 100644 --- a/src/PhpWord/Writer/ODText/Part/Styles.php +++ b/src/PhpWord/Writer/ODText/Part/Styles.php @@ -17,11 +17,12 @@ namespace PhpOffice\PhpWord\Writer\ODText\Part; -use PhpOffice\PhpWord\PhpWord; +use PhpOffice\PhpWord\Settings; +use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Style; /** - * ODText styloes part writer: styles.xml + * ODText styles part writer: styles.xml */ class Styles extends AbstractPart { @@ -36,22 +37,38 @@ class Styles extends AbstractPart // XML header $xmlWriter->startDocument('1.0', 'UTF-8'); - - // Styles:Styles $xmlWriter->startElement('office:document-styles'); $this->writeCommonRootAttributes($xmlWriter); - // office:font-face-decls + // Font declarations $this->writeFontFaces($xmlWriter); - // office:styles + // Office styles $xmlWriter->startElement('office:styles'); + $this->writeDefault($xmlWriter); + $this->writeNamed($xmlWriter); + $xmlWriter->endElement(); - // style:default-style + // Automatic styles + $xmlWriter->startElement('office:automatic-styles'); + $this->writePageLayout($xmlWriter); + $this->writeMaster($xmlWriter); + $xmlWriter->endElement(); + + $xmlWriter->endElement(); // office:document-styles + + return $xmlWriter->getData(); + } + + /** + * Write default styles + */ + private function writeDefault(XMLWriter $xmlWriter) + { $xmlWriter->startElement('style:default-style'); $xmlWriter->writeAttribute('style:family', 'paragraph'); - // style:paragraph-properties + // Paragraph $xmlWriter->startElement('style:paragraph-properties'); $xmlWriter->writeAttribute('fo:hyphenation-ladder-count', 'no-limit'); $xmlWriter->writeAttribute('style:text-autospace', 'ideograph-alpha'); @@ -59,54 +76,59 @@ class Styles extends AbstractPart $xmlWriter->writeAttribute('style:line-break', 'strict'); $xmlWriter->writeAttribute('style:tab-stop-distance', '1.249cm'); $xmlWriter->writeAttribute('style:writing-mode', 'page'); - $xmlWriter->endElement(); + $xmlWriter->endElement(); // style:paragraph-properties - // style:text-properties + // Font $xmlWriter->startElement('style:text-properties'); $xmlWriter->writeAttribute('style:use-window-font-color', 'true'); - $xmlWriter->writeAttribute('style:font-name', PhpWord::DEFAULT_FONT_NAME); - $xmlWriter->writeAttribute('fo:font-size', PhpWord::DEFAULT_FONT_SIZE . 'pt'); + $xmlWriter->writeAttribute('style:font-name', Settings::getDefaultFontName()); + $xmlWriter->writeAttribute('fo:font-size', Settings::getDefaultFontSize() . 'pt'); $xmlWriter->writeAttribute('fo:language', 'fr'); $xmlWriter->writeAttribute('fo:country', 'FR'); $xmlWriter->writeAttribute('style:letter-kerning', 'true'); - $xmlWriter->writeAttribute('style:font-name-asian', PhpWord::DEFAULT_FONT_NAME . '2'); - $xmlWriter->writeAttribute('style:font-size-asian', PhpWord::DEFAULT_FONT_SIZE . 'pt'); + $xmlWriter->writeAttribute('style:font-name-asian', Settings::getDefaultFontName() . '2'); + $xmlWriter->writeAttribute('style:font-size-asian', Settings::getDefaultFontSize() . 'pt'); $xmlWriter->writeAttribute('style:language-asian', 'zh'); $xmlWriter->writeAttribute('style:country-asian', 'CN'); - $xmlWriter->writeAttribute('style:font-name-complex', PhpWord::DEFAULT_FONT_NAME . '2'); - $xmlWriter->writeAttribute('style:font-size-complex', PhpWord::DEFAULT_FONT_SIZE . 'pt'); + $xmlWriter->writeAttribute('style:font-name-complex', Settings::getDefaultFontName() . '2'); + $xmlWriter->writeAttribute('style:font-size-complex', Settings::getDefaultFontSize() . 'pt'); $xmlWriter->writeAttribute('style:language-complex', 'hi'); $xmlWriter->writeAttribute('style:country-complex', 'IN'); $xmlWriter->writeAttribute('fo:hyphenate', 'false'); $xmlWriter->writeAttribute('fo:hyphenation-remain-char-count', '2'); $xmlWriter->writeAttribute('fo:hyphenation-push-char-count', '2'); - $xmlWriter->endElement(); + $xmlWriter->endElement(); // style:text-properties - $xmlWriter->endElement(); + $xmlWriter->endElement(); // style:default-style + } - // Write Style Definitions + /** + * Write named styles + */ + private function writeNamed(XMLWriter $xmlWriter) + { $styles = Style::getStyles(); if (count($styles) > 0) { - foreach ($styles as $styleName => $style) { - if (preg_match('#^T[0-9]+$#', $styleName) == 0 - && preg_match('#^P[0-9]+$#', $styleName) == 0 - ) { + foreach ($styles as $style) { + if ($style->isAuto() === false) { $styleClass = str_replace('\\Style\\', '\\Writer\\ODText\\Style\\', get_class($style)); if (class_exists($styleClass)) { + /** @var $styleWriter \PhpOffice\PhpWord\Writer\ODText\Style\AbstractStyle Type hint */ $styleWriter = new $styleClass($xmlWriter, $style); $styleWriter->write(); } } } } - $xmlWriter->endElement(); - - // office:automatic-styles - $xmlWriter->startElement('office:automatic-styles'); - // style:page-layout + } + /** + * Write page layout styles + */ + private function writePageLayout(XMLWriter $xmlWriter) + { $xmlWriter->startElement('style:page-layout'); $xmlWriter->writeAttribute('style:name', 'Mpm1'); - // style:page-layout-properties + $xmlWriter->startElement('style:page-layout-properties'); $xmlWriter->writeAttribute('fo:page-width', "21.001cm"); $xmlWriter->writeAttribute('fo:page-height', '29.7cm'); @@ -128,36 +150,38 @@ class Styles extends AbstractPart $xmlWriter->writeAttribute('style:layout-grid-base-width', '0.37cm'); $xmlWriter->writeAttribute('style:layout-grid-snap-to', 'true'); $xmlWriter->writeAttribute('style:footnote-max-height', '0cm'); - //style:footnote-sep + $xmlWriter->startElement('style:footnote-sep'); $xmlWriter->writeAttribute('style:width', '0.018cm'); $xmlWriter->writeAttribute('style:line-style', 'solid'); $xmlWriter->writeAttribute('style:adjustment', 'left'); $xmlWriter->writeAttribute('style:rel-width', '25%'); $xmlWriter->writeAttribute('style:color', '#000000'); - $xmlWriter->endElement(); - $xmlWriter->endElement(); - // style:header-style - $xmlWriter->startElement('style:header-style'); - $xmlWriter->endElement(); - // style:footer-style - $xmlWriter->startElement('style:footer-style'); - $xmlWriter->endElement(); - $xmlWriter->endElement(); - $xmlWriter->endElement(); + $xmlWriter->endElement(); //style:footnote-sep - // office:master-styles + $xmlWriter->endElement(); // style:page-layout-properties + + + $xmlWriter->startElement('style:header-style'); + $xmlWriter->endElement(); // style:header-style + + $xmlWriter->startElement('style:footer-style'); + $xmlWriter->endElement(); // style:footer-style + + $xmlWriter->endElement(); // style:page-layout + } + /** + * Write master style + */ + private function writeMaster(XMLWriter $xmlWriter) + { $xmlWriter->startElement('office:master-styles'); - // style:master-page + $xmlWriter->startElement('style:master-page'); $xmlWriter->writeAttribute('style:name', 'Standard'); $xmlWriter->writeAttribute('style:page-layout-name', 'Mpm1'); - $xmlWriter->endElement(); - $xmlWriter->endElement(); + $xmlWriter->endElement(); // style:master-page - $xmlWriter->endElement(); - - // Return - return $xmlWriter->getData(); + $xmlWriter->endElement(); // office:master-styles } } diff --git a/src/PhpWord/Writer/ODText/Style/AbstractStyle.php b/src/PhpWord/Writer/ODText/Style/AbstractStyle.php index 5e4a7939..18d6ce10 100644 --- a/src/PhpWord/Writer/ODText/Style/AbstractStyle.php +++ b/src/PhpWord/Writer/ODText/Style/AbstractStyle.php @@ -17,11 +17,13 @@ namespace PhpOffice\PhpWord\Writer\ODText\Style; +use PhpOffice\PhpWord\Writer\Word2007\Style\AbstractStyle as Word2007AbstractStyle; + /** * Style writer * * @since 0.10.0 */ -abstract class AbstractStyle extends \PhpOffice\PhpWord\Writer\Word2007\Style\AbstractStyle +abstract class AbstractStyle extends Word2007AbstractStyle { } diff --git a/src/PhpWord/Writer/ODText/Style/Font.php b/src/PhpWord/Writer/ODText/Style/Font.php index eb96946c..acab0ee5 100644 --- a/src/PhpWord/Writer/ODText/Style/Font.php +++ b/src/PhpWord/Writer/ODText/Style/Font.php @@ -24,11 +24,6 @@ namespace PhpOffice\PhpWord\Writer\ODText\Style; */ class Font extends AbstractStyle { - /** - * Is automatic style - */ - private $isAuto = false; - /** * Write style */ @@ -47,18 +42,18 @@ class Font extends AbstractStyle // Name $font = $style->getName(); - $xmlWriter->writeAttributeIf($font, 'style:font-name', $font); - $xmlWriter->writeAttributeIf($font, 'style:font-name-complex', $font); + $xmlWriter->writeAttributeIf($font != '', 'style:font-name', $font); + $xmlWriter->writeAttributeIf($font != '', 'style:font-name-complex', $font); $size = $style->getSize(); // Size - $xmlWriter->writeAttributeIf($size, 'fo:font-size', $size . 'pt'); - $xmlWriter->writeAttributeIf($size, 'style:font-size-asian', $size . 'pt'); - $xmlWriter->writeAttributeIf($size, 'style:font-size-complex', $size . 'pt'); + $xmlWriter->writeAttributeIf(is_numeric($size), 'fo:font-size', $size . 'pt'); + $xmlWriter->writeAttributeIf(is_numeric($size), 'style:font-size-asian', $size . 'pt'); + $xmlWriter->writeAttributeIf(is_numeric($size), 'style:font-size-complex', $size . 'pt'); // Color $color = $style->getColor(); - $xmlWriter->writeAttributeIf($color, 'fo:color', '#' . $color); + $xmlWriter->writeAttributeIf($color != '', 'fo:color', '#' . $color); // Bold & italic $xmlWriter->writeAttributeIf($style->isBold(), 'fo:font-weight', 'bold'); @@ -67,17 +62,28 @@ class Font extends AbstractStyle $xmlWriter->writeAttributeIf($style->isItalic(), 'style:font-style-asian', 'italic'); $xmlWriter->writeAttributeIf($style->isItalic(), 'style:font-style-complex', 'italic'); + // Underline + // @todo Various mode of underline + $underline = $style->getUnderline(); + $xmlWriter->writeAttributeIf($underline != 'none', 'style:text-underline-style', 'solid'); + + // Strikethrough, double strikethrough + $xmlWriter->writeAttributeIf($style->isStrikethrough(), 'style:text-line-through-type', 'single'); + $xmlWriter->writeAttributeIf($style->isDoubleStrikethrough(), 'style:text-line-through-type', 'double'); + + // Small caps, all caps + $xmlWriter->writeAttributeIf($style->isSmallCaps(), 'fo:font-variant', 'small-caps'); + $xmlWriter->writeAttributeIf($style->isAllCaps(), 'fo:text-transform', 'uppercase'); + + // Superscript/subscript + $xmlWriter->writeAttributeIf($style->isSuperScript(), 'style:text-position', 'super'); + $xmlWriter->writeAttributeIf($style->isSubScript(), 'style:text-position', 'sub'); + + // @todo Foreground-Color + + // @todo Background color + $xmlWriter->endElement(); // style:text-properties $xmlWriter->endElement(); // style:style } - - /** - * Set is automatic style - * - * @param bool $value - */ - public function setIsAuto($value) - { - $this->isAuto = $value; - } } diff --git a/src/PhpWord/Writer/ODText/Style/Image.php b/src/PhpWord/Writer/ODText/Style/Image.php new file mode 100644 index 00000000..de97f474 --- /dev/null +++ b/src/PhpWord/Writer/ODText/Style/Image.php @@ -0,0 +1,49 @@ +getStyle(); + if (!$style instanceof \PhpOffice\PhpWord\Style\Image) { + return; + } + $xmlWriter = $this->getXmlWriter(); + + $xmlWriter->startElement('style:style'); + $xmlWriter->writeAttribute('style:name', $style->getStyleName()); + $xmlWriter->writeAttribute('style:family', 'graphic'); + $xmlWriter->writeAttribute('style:parent-style-name', 'Graphics'); + $xmlWriter->startElement('style:graphic-properties'); + $xmlWriter->writeAttribute('style:vertical-pos', 'top'); + $xmlWriter->writeAttribute('style:vertical-rel', 'baseline'); + $xmlWriter->endElement(); // style:graphic-properties + $xmlWriter->endElement(); // style:style + } +} diff --git a/src/PhpWord/Writer/ODText/Style/Paragraph.php b/src/PhpWord/Writer/ODText/Style/Paragraph.php index e5f52cfe..133b8cdf 100644 --- a/src/PhpWord/Writer/ODText/Style/Paragraph.php +++ b/src/PhpWord/Writer/ODText/Style/Paragraph.php @@ -24,11 +24,6 @@ namespace PhpOffice\PhpWord\Writer\ODText\Style; */ class Paragraph extends AbstractStyle { - /** - * Is automatic style - */ - private $isAuto = false; - /** * Write style */ @@ -46,13 +41,13 @@ class Paragraph extends AbstractStyle $xmlWriter->startElement('style:style'); $xmlWriter->writeAttribute('style:name', $style->getStyleName()); $xmlWriter->writeAttribute('style:family', 'paragraph'); - if ($this->isAuto) { + if ($style->isAuto()) { $xmlWriter->writeAttribute('style:parent-style-name', 'Standard'); $xmlWriter->writeAttribute('style:master-page-name', 'Standard'); } $xmlWriter->startElement('style:paragraph-properties'); - if ($this->isAuto) { + if ($style->isAuto()) { $xmlWriter->writeAttribute('style:page-number', 'auto'); } else { $xmlWriter->writeAttribute('fo:margin-top', $marginTop . 'cm'); @@ -63,14 +58,4 @@ class Paragraph extends AbstractStyle $xmlWriter->endElement(); //style:style } - - /** - * Set is automatic style - * - * @param bool $value - */ - public function setIsAuto($value) - { - $this->isAuto = $value; - } } diff --git a/src/PhpWord/Writer/ODText/Style/Section.php b/src/PhpWord/Writer/ODText/Style/Section.php new file mode 100644 index 00000000..3d910157 --- /dev/null +++ b/src/PhpWord/Writer/ODText/Style/Section.php @@ -0,0 +1,51 @@ +getStyle(); + if (!$style instanceof \PhpOffice\PhpWord\Style\Section) { + return; + } + $xmlWriter = $this->getXmlWriter(); + + $xmlWriter->startElement('style:style'); + $xmlWriter->writeAttribute('style:name', $style->getStyleName()); + $xmlWriter->writeAttribute('style:family', "section"); + $xmlWriter->startElement('style:section-properties'); + + $xmlWriter->startElement('style:columns'); + $xmlWriter->writeAttribute('fo:column-count', $style->getColsNum()); + $xmlWriter->endElement(); // style:columns + + $xmlWriter->endElement(); // style:section-properties + $xmlWriter->endElement(); // style:style + } +} diff --git a/src/PhpWord/Writer/ODText/Style/Table.php b/src/PhpWord/Writer/ODText/Style/Table.php new file mode 100644 index 00000000..b32349af --- /dev/null +++ b/src/PhpWord/Writer/ODText/Style/Table.php @@ -0,0 +1,49 @@ +getStyle(); + if (!$style instanceof \PhpOffice\PhpWord\Style\Table) { + return; + } + $xmlWriter = $this->getXmlWriter(); + + $xmlWriter->startElement('style:style'); + $xmlWriter->writeAttribute('style:name', $style->getStyleName()); + $xmlWriter->writeAttribute('style:family', 'table'); + $xmlWriter->startElement('style:table-properties'); + //$xmlWriter->writeAttribute('style:width', 'table'); + $xmlWriter->writeAttribute('style:rel-width', 100); + $xmlWriter->writeAttribute('table:align', 'center'); + $xmlWriter->endElement(); // style:table-properties + $xmlWriter->endElement(); // style:style + } +} diff --git a/src/PhpWord/Writer/PDF.php b/src/PhpWord/Writer/PDF.php index 45e8a412..98dc1220 100644 --- a/src/PhpWord/Writer/PDF.php +++ b/src/PhpWord/Writer/PDF.php @@ -23,6 +23,8 @@ use PhpOffice\PhpWord\Settings; /** * PDF Writer + * + * @since 0.10.0 */ class PDF { @@ -37,6 +39,7 @@ class PDF * Instantiate a new renderer of the configured type within this container class * * @param \PhpOffice\PhpWord\PhpWord $phpWord + * @throws \PhpOffice\PhpWord\Exception\Exception */ public function __construct(PhpWord $phpWord) { @@ -62,6 +65,7 @@ class PDF * @param string $name Renderer library method name * @param mixed[] $arguments Array of arguments to pass to the renderer method * @return mixed Returned data from the PDF renderer wrapper method + * @throws \PhpOffice\PhpWord\Exception\Exception */ public function __call($name, $arguments) { diff --git a/src/PhpWord/Writer/PDF/AbstractRenderer.php b/src/PhpWord/Writer/PDF/AbstractRenderer.php index 342cdf58..f7266d1a 100644 --- a/src/PhpWord/Writer/PDF/AbstractRenderer.php +++ b/src/PhpWord/Writer/PDF/AbstractRenderer.php @@ -19,12 +19,23 @@ namespace PhpOffice\PhpWord\Writer\PDF; use PhpOffice\PhpWord\Exception\Exception; use PhpOffice\PhpWord\PhpWord; +use PhpOffice\PhpWord\Settings; +use PhpOffice\PhpWord\Writer\HTML; /** * Abstract PDF renderer + * + * @since 0.10.0 */ -abstract class AbstractRenderer extends \PhpOffice\PhpWord\Writer\HTML +abstract class AbstractRenderer extends HTML { + /** + * Name of renderer include file + * + * @var string + */ + protected $includeFile; + /** * Temporary storage directory * @@ -44,14 +55,14 @@ abstract class AbstractRenderer extends \PhpOffice\PhpWord\Writer\HTML * * @var int */ - protected $paperSize = null; + protected $paperSize; /** * Orientation * * @var string */ - protected $orientation = null; + protected $orientation; /** * Paper Sizes xRef List @@ -66,10 +77,17 @@ abstract class AbstractRenderer extends \PhpOffice\PhpWord\Writer\HTML * Create new instance * * @param PhpWord $phpWord PhpWord object + * @throws \PhpOffice\PhpWord\Exception\Exception */ public function __construct(PhpWord $phpWord) { parent::__construct($phpWord); + $includeFile = Settings::getPdfRendererPath() . '/' . $this->includeFile; + if (file_exists($includeFile)) { + require_once $includeFile; + } else { + throw new Exception('Unable to load PDF Rendering library'); + } } /** @@ -90,10 +108,12 @@ abstract class AbstractRenderer extends \PhpOffice\PhpWord\Writer\HTML * 'arialunicid0-japanese' * * @param string $fontName + * @return self */ public function setFont($fontName) { $this->font = $fontName; + return $this; } @@ -110,12 +130,12 @@ abstract class AbstractRenderer extends \PhpOffice\PhpWord\Writer\HTML /** * Set Paper Size * - * @param int $pValue Paper size = PAPERSIZE_A4 + * @param int $value Paper size = PAPERSIZE_A4 * @return self */ - public function setPaperSize($pValue = 9) + public function setPaperSize($value = 9) { - $this->paperSize = $pValue; + $this->paperSize = $value; return $this; } @@ -132,26 +152,27 @@ abstract class AbstractRenderer extends \PhpOffice\PhpWord\Writer\HTML /** * Set Orientation * - * @param string $pValue Page orientation ORIENTATION_DEFAULT + * @param string $value Page orientation ORIENTATION_DEFAULT * @return self */ - public function setOrientation($pValue = 'default') + public function setOrientation($value = 'default') { - $this->orientation = $pValue; + $this->orientation = $value; return $this; } /** * Save PhpWord to PDF file, pre-save * - * @param string $pFilename Name of the file to save as + * @param string $filename Name of the file to save as * @return resource + * @throws \PhpOffice\PhpWord\Exception\Exception */ - protected function prepareForSave($pFilename = null) + protected function prepareForSave($filename = null) { - $fileHandle = fopen($pFilename, 'w'); + $fileHandle = fopen($filename, 'w'); if ($fileHandle === false) { - throw new Exception("Could not open file $pFilename for writing."); + throw new Exception("Could not open file $filename for writing."); } $this->isPdf = true; diff --git a/src/PhpWord/Writer/PDF/DomPDF.php b/src/PhpWord/Writer/PDF/DomPDF.php index cf18d7a5..4effc154 100644 --- a/src/PhpWord/Writer/PDF/DomPDF.php +++ b/src/PhpWord/Writer/PDF/DomPDF.php @@ -17,56 +17,39 @@ namespace PhpOffice\PhpWord\Writer\PDF; -use PhpOffice\PhpWord\Exception\Exception; -use PhpOffice\PhpWord\PhpWord; -use PhpOffice\PhpWord\Settings; +use PhpOffice\PhpWord\Writer\WriterInterface; /** * DomPDF writer + * + * @link https://github.com/dompdf/dompdf + * @since 0.10.0 */ -class DomPDF extends AbstractRenderer implements \PhpOffice\PhpWord\Writer\WriterInterface +class DomPDF extends AbstractRenderer implements WriterInterface { /** - * Create new instance + * Name of renderer include file * - * @param PhpWord $phpWord PhpWord object + * @var string */ - public function __construct(PhpWord $phpWord) - { - parent::__construct($phpWord); - $configFile = Settings::getPdfRendererPath() . '/dompdf_config.inc.php'; - if (file_exists($configFile)) { - require_once $configFile; - } else { - throw new Exception('Unable to load PDF Rendering library'); - } - } + protected $includeFile = 'dompdf_config.inc.php'; /** * Save PhpWord to file * - * @param string $pFilename Name of the file to save as - * @throws Exception + * @param string $filename Name of the file to save as */ - public function save($pFilename = null) + public function save($filename = null) { - $fileHandle = parent::prepareForSave($pFilename); + $fileHandle = parent::prepareForSave($filename); - // Default PDF paper size + // PDF settings $paperSize = 'A4'; - $orientation = 'P'; - $printPaperSize = 9; - - if (isset(self::$paperSizes[$printPaperSize])) { - $paperSize = self::$paperSizes[$printPaperSize]; - } - - $orientation = ($orientation == 'L') ? 'landscape' : 'portrait'; + $orientation = 'portrait'; // Create PDF $pdf = new \DOMPDF(); $pdf->set_paper(strtolower($paperSize), $orientation); - $pdf->load_html($this->writeDocument()); $pdf->render(); diff --git a/src/PhpWord/Writer/PDF/MPDF.php b/src/PhpWord/Writer/PDF/MPDF.php new file mode 100644 index 00000000..d38d5b66 --- /dev/null +++ b/src/PhpWord/Writer/PDF/MPDF.php @@ -0,0 +1,71 @@ +_setPageSize($paperSize, $orientation); + $pdf->addPage($orientation); + + // Write document properties + $phpWord = $this->getPhpWord(); + $docProps = $phpWord->getDocumentProperties(); + $pdf->setTitle($docProps->getTitle()); + $pdf->setAuthor($docProps->getCreator()); + $pdf->setSubject($docProps->getSubject()); + $pdf->setKeywords($docProps->getKeywords()); + $pdf->setCreator($docProps->getCreator()); + + $pdf->writeHTML($this->writeDocument()); + + // Write to file + fwrite($fileHandle, $pdf->output($filename, 'S')); + + parent::restoreStateAfterSave($fileHandle); + } +} diff --git a/src/PhpWord/Writer/PDF/TCPDF.php b/src/PhpWord/Writer/PDF/TCPDF.php new file mode 100644 index 00000000..05f02756 --- /dev/null +++ b/src/PhpWord/Writer/PDF/TCPDF.php @@ -0,0 +1,73 @@ +setFontSubsetting(false); + $pdf->setPrintHeader(false); + $pdf->setPrintFooter(false); + $pdf->addPage(); + $pdf->setFont($this->getFont()); + $pdf->writeHTML($this->writeDocument()); + + // Write document properties + $phpWord = $this->getPhpWord(); + $docProps = $phpWord->getDocumentProperties(); + $pdf->setTitle($docProps->getTitle()); + $pdf->setAuthor($docProps->getCreator()); + $pdf->setSubject($docProps->getSubject()); + $pdf->setKeywords($docProps->getKeywords()); + $pdf->setCreator($docProps->getCreator()); + + // Write to file + fwrite($fileHandle, $pdf->output($filename, 'S')); + + parent::restoreStateAfterSave($fileHandle); + } +} diff --git a/src/PhpWord/Writer/RTF.php b/src/PhpWord/Writer/RTF.php index 434ffd67..315e6007 100644 --- a/src/PhpWord/Writer/RTF.php +++ b/src/PhpWord/Writer/RTF.php @@ -17,9 +17,9 @@ namespace PhpOffice\PhpWord\Writer; -use PhpOffice\PhpWord\Element\Text; use PhpOffice\PhpWord\Exception\Exception; use PhpOffice\PhpWord\PhpWord; +use PhpOffice\PhpWord\Settings; use PhpOffice\PhpWord\Shared\Drawing; use PhpOffice\PhpWord\Style; use PhpOffice\PhpWord\Style\Font; @@ -59,7 +59,6 @@ class RTF extends AbstractWriter implements WriterInterface */ public function __construct(PhpWord $phpWord = null) { - // Assign PhpWord $this->setPhpWord($phpWord); } @@ -71,10 +70,6 @@ class RTF extends AbstractWriter implements WriterInterface */ public function save($filename = null) { - if (is_null($this->phpWord)) { - throw new Exception('PhpWord object unassigned.'); - } - $filename = $this->getTempFile($filename); $hFile = fopen($filename, 'w'); if ($hFile !== false) { @@ -146,7 +141,7 @@ class RTF extends AbstractWriter implements WriterInterface // Set the color tbl group $content .= '{\colortbl '; - foreach ($this->colorTable as $idx => $color) { + foreach ($this->colorTable as $color) { $arrColor = Drawing::htmlToRGB($color); $content .= ';\red' . $arrColor[0] . '\green' . $arrColor[1] . '\blue' . $arrColor[2] . ''; } @@ -159,7 +154,7 @@ class RTF extends AbstractWriter implements WriterInterface $content .= '\nowidctlpar'; // No widow/orphan control $content .= '\lang1036'; // Applies a language to a text run (1036 : French (France)) $content .= '\kerning1'; // Point size (in half-points) above which to kern character pairs - $content .= '\fs' . (PhpWord::DEFAULT_FONT_SIZE * 2); // Set the font size in half-points + $content .= '\fs' . (Settings::getDefaultFontSize() * 2); // Set the font size in half-points $content .= PHP_EOL; // Body @@ -195,12 +190,9 @@ class RTF extends AbstractWriter implements WriterInterface */ private function populateFontTable() { - $phpWord = $this->phpWord; - - $arrFonts = array(); - // Default font : PhpWord::DEFAULT_FONT_NAME - $arrFonts[] = PhpWord::DEFAULT_FONT_NAME; - // PhpWord object : $this->phpWord + $phpWord = $this->getPhpWord(); + $fontTable = array(); + $fontTable[] = Settings::getDefaultFontName(); // Browse styles $styles = Style::getStyles(); @@ -208,8 +200,8 @@ class RTF extends AbstractWriter implements WriterInterface foreach ($styles as $style) { // Font if ($style instanceof Font) { - if (in_array($style->getName(), $arrFonts) == false) { - $arrFonts[] = $style->getName(); + if (in_array($style->getName(), $fontTable) == false) { + $fontTable[] = $style->getName(); } } } @@ -219,19 +211,14 @@ class RTF extends AbstractWriter implements WriterInterface $sections = $phpWord->getSections(); $countSections = count($sections); if ($countSections > 0) { - $pSection = 0; - foreach ($sections as $section) { - $pSection++; $elements = $section->getElements(); - foreach ($elements as $element) { - if ($element instanceof Text) { + if (method_exists($element, 'getFontStyle')) { $fontStyle = $element->getFontStyle(); - if ($fontStyle instanceof Font) { - if (in_array($fontStyle->getName(), $arrFonts) == false) { - $arrFonts[] = $fontStyle->getName(); + if (in_array($fontStyle->getName(), $fontTable) == false) { + $fontTable[] = $fontStyle->getName(); } } } @@ -239,7 +226,7 @@ class RTF extends AbstractWriter implements WriterInterface } } - return $arrFonts; + return $fontTable; } /** @@ -249,11 +236,9 @@ class RTF extends AbstractWriter implements WriterInterface */ private function populateColorTable() { - $phpWord = $this->phpWord; - $defaultFontColor = PhpWord::DEFAULT_FONT_COLOR; - - $arrColors = array(); - // PhpWord object : $this->phpWord + $phpWord = $this->getPhpWord(); + $defaultFontColor = Settings::DEFAULT_FONT_COLOR; + $colorTable = array(); // Browse styles $styles = Style::getStyles(); @@ -263,11 +248,11 @@ class RTF extends AbstractWriter implements WriterInterface if ($style instanceof Font) { $color = $style->getColor(); $fgcolor = $style->getFgColor(); - if (!in_array($color, $arrColors) && $color != $defaultFontColor && !empty($color)) { - $arrColors[] = $color; + if (!in_array($color, $colorTable) && $color != $defaultFontColor && !empty($color)) { + $colorTable[] = $color; } - if (!in_array($fgcolor, $arrColors) && $fgcolor != $defaultFontColor && !empty($fgcolor)) { - $arrColors[] = $fgcolor; + if (!in_array($fgcolor, $colorTable) && $fgcolor != $defaultFontColor && !empty($fgcolor)) { + $colorTable[] = $fgcolor; } } } @@ -277,22 +262,17 @@ class RTF extends AbstractWriter implements WriterInterface $sections = $phpWord->getSections(); $countSections = count($sections); if ($countSections > 0) { - $pSection = 0; - foreach ($sections as $section) { - $pSection++; $elements = $section->getElements(); - foreach ($elements as $element) { - if ($element instanceof Text) { + if (method_exists($element, 'getFontStyle')) { $fontStyle = $element->getFontStyle(); - if ($fontStyle instanceof Font) { - if (in_array($fontStyle->getColor(), $arrColors) == false) { - $arrColors[] = $fontStyle->getColor(); + if (in_array($fontStyle->getColor(), $colorTable) == false) { + $colorTable[] = $fontStyle->getColor(); } - if (in_array($fontStyle->getFgColor(), $arrColors) == false) { - $arrColors[] = $fontStyle->getFgColor(); + if (in_array($fontStyle->getFgColor(), $colorTable) == false) { + $colorTable[] = $fontStyle->getFgColor(); } } } @@ -300,6 +280,6 @@ class RTF extends AbstractWriter implements WriterInterface } } - return $arrColors; + return $colorTable; } } diff --git a/src/PhpWord/Writer/RTF/Element/AbstractElement.php b/src/PhpWord/Writer/RTF/Element/AbstractElement.php index fbf8114e..7af93180 100644 --- a/src/PhpWord/Writer/RTF/Element/AbstractElement.php +++ b/src/PhpWord/Writer/RTF/Element/AbstractElement.php @@ -17,11 +17,147 @@ namespace PhpOffice\PhpWord\Writer\RTF\Element; +use PhpOffice\PhpWord\Shared\String; +use PhpOffice\PhpWord\Style\Font as FontStyle; +use PhpOffice\PhpWord\Style; +use PhpOffice\PhpWord\Style\Paragraph as ParagraphStyle; +use PhpOffice\PhpWord\Writer\HTML\Element\AbstractElement as HTMLAbstractElement; +use PhpOffice\PhpWord\Writer\RTF\Style\Font as FontStyleWriter; +use PhpOffice\PhpWord\Writer\RTF\Style\Paragraph as ParagraphStyleWriter; + /** * Abstract RTF element writer * * @since 0.11.0 */ -class AbstractElement extends \PhpOffice\PhpWord\Writer\HTML\Element\AbstractElement +abstract class AbstractElement extends HTMLAbstractElement { + /** + * Font style + * + * @var \PhpOffice\PhpWord\Style\Font + */ + private $fontStyle; + + /** + * Paragraph style + * + * @var \PhpOffice\PhpWord\Style\Paragraph + */ + private $paragraphStyle; + + /** + * Get font and paragraph styles + */ + protected function getStyles() + { + /** @var \PhpOffice\PhpWord\Writer\RTF $parentWriter Type hint */ + $parentWriter = $this->parentWriter; + + /** @var \PhpOffice\PhpWord\Element\Text $element Type hint */ + $element = $this->element; + + // Font style + if (method_exists($element, 'getFontStyle')) { + $this->fontStyle = $element->getFontStyle(); + if (is_string($this->fontStyle)) { + $this->fontStyle = Style::getStyle($this->fontStyle); + } + } + + // Paragraph style + if (method_exists($element, 'getParagraphStyle')) { + $this->paragraphStyle = $element->getParagraphStyle(); + if (is_string($this->paragraphStyle)) { + $this->paragraphStyle = Style::getStyle($this->paragraphStyle); + } + + if ($this->paragraphStyle !== null && !$this->withoutP) { + if ($parentWriter->getLastParagraphStyle() != $element->getParagraphStyle()) { + $parentWriter->setLastParagraphStyle($element->getParagraphStyle()); + } else { + $parentWriter->setLastParagraphStyle(); + $this->paragraphStyle = null; + } + } else { + $parentWriter->setLastParagraphStyle(); + $this->paragraphStyle = null; + } + } + } + + /** + * Write opening + * + * @return string + */ + protected function writeOpening() + { + if ($this->withoutP || !$this->paragraphStyle instanceof ParagraphStyle) { + return ''; + } + + $styleWriter = new ParagraphStyleWriter($this->paragraphStyle); + return $styleWriter->write(); + } + + /** + * Write text + * + * @param string $text + * @return string + */ + protected function writeText($text) + { + return String::toUnicode($text); + } + + /** + * Write closing + * + * @return string + */ + protected function writeClosing() + { + if ($this->withoutP) { + return ''; + } + + return '\par' . PHP_EOL; + } + + /** + * Write font style + * + * @return string + */ + protected function writeFontStyle() + { + if (!$this->fontStyle instanceof FontStyle) { + return ''; + } + + /** @var \PhpOffice\PhpWord\Writer\RTF $parentWriter Type hint */ + $parentWriter = $this->parentWriter; + + // Create style writer and set color/name index + $styleWriter = new FontStyleWriter($this->fontStyle); + if ($this->fontStyle->getColor() != null) { + $colorIndex = array_search($this->fontStyle->getColor(), $parentWriter->getColorTable()); + if ($colorIndex !== false) { + $styleWriter->setColorIndex($colorIndex + 1); + } + } + if ($this->fontStyle->getName() != null) { + $fontIndex = array_search($this->fontStyle->getName(), $parentWriter->getFontTable()); + if ($fontIndex !== false) { + $styleWriter->setNameIndex($fontIndex); + } + } + + // Write style + $content = $styleWriter->write(); + + return $content; + } } diff --git a/src/PhpWord/Writer/RTF/Element/Container.php b/src/PhpWord/Writer/RTF/Element/Container.php index 57127eb8..cb95b84b 100644 --- a/src/PhpWord/Writer/RTF/Element/Container.php +++ b/src/PhpWord/Writer/RTF/Element/Container.php @@ -17,36 +17,19 @@ namespace PhpOffice\PhpWord\Writer\RTF\Element; +use PhpOffice\PhpWord\Writer\HTML\Element\Container as HTMLContainer; + /** * Container element RTF writer * * @since 0.11.0 */ -class Container extends \PhpOffice\PhpWord\Writer\HTML\Element\Container +class Container extends HTMLContainer { /** - * Write container + * Namespace; Can't use __NAMESPACE__ in inherited class (RTF) * - * @return string + * @var string */ - public function write() - { - $container = $this->element; - $containerClass = substr(get_class($container), strrpos(get_class($container), '\\') + 1); - $withoutP = in_array($containerClass, array('TextRun', 'Footnote', 'Endnote')) ? true : false; - $content = ''; - - $elements = $container->getElements(); - foreach ($elements as $element) { - $writerClass = str_replace('\\Element', '\\Writer\\RTF\\Element', get_class($element)); - if (class_exists($writerClass)) { - $writer = new $writerClass($this->parentWriter, $element, $withoutP); - $content .= '{'; - $content .= $writer->write(); - $content .= '}' . PHP_EOL; - } - } - - return $content; - } + protected $namespace = 'PhpOffice\\PhpWord\\Writer\\RTF\\Element'; } diff --git a/src/PhpWord/Writer/RTF/Element/Link.php b/src/PhpWord/Writer/RTF/Element/Link.php new file mode 100644 index 00000000..22b08588 --- /dev/null +++ b/src/PhpWord/Writer/RTF/Element/Link.php @@ -0,0 +1,50 @@ +element instanceof \PhpOffice\PhpWord\Element\Link) { + return ''; + } + + $this->getStyles(); + + $content = ''; + $content .= $this->writeOpening(); + $content .= '{\field {\*\fldinst {HYPERLINK "' . $this->element->getTarget() . '"}}{\\fldrslt {'; + $content .= $this->writeFontStyle(); + $content .= $this->writeText($this->element->getText()); + $content .= '}}}'; + $content .= $this->writeClosing(); + + return $content; + } +} diff --git a/src/PhpWord/Writer/RTF/Element/ListItem.php b/src/PhpWord/Writer/RTF/Element/ListItem.php new file mode 100644 index 00000000..b795143c --- /dev/null +++ b/src/PhpWord/Writer/RTF/Element/ListItem.php @@ -0,0 +1,27 @@ +getFontStyle(); - - $content = ''; - $content .= $this->writeParagraphStyle(); - $content .= $this->writeFontStyleBegin($fontStyle); - if ($this->parentWriter->getLastParagraphStyle() != '' || $fontStyle) { - $content .= ' '; - } - $content .= $this->element->getText(); - $content .= $this->writeFontStyleEnd($fontStyle); - - if (!$this->withoutP) { - $content .= '\par' . PHP_EOL; - } - - return $content; - } - - /** - * Write paragraph style - * - * @return string - */ - private function writeParagraphStyle() - { - $content = ''; - - // Get paragraph style - $paragraphStyle = $this->element->getParagraphStyle(); - if (is_string($paragraphStyle)) { - $paragraphStyle = Style::getStyle($paragraphStyle); - } - - // Write style when applicable - if ($paragraphStyle && !$this->withoutP) { - if ($this->parentWriter->getLastParagraphStyle() != $this->element->getParagraphStyle()) { - $styleWriter = new ParagraphStyleWriter($paragraphStyle); - $content = $styleWriter->write(); - $this->parentWriter->setLastParagraphStyle($this->element->getParagraphStyle()); - } else { - $this->parentWriter->setLastParagraphStyle(); - } - } else { - $this->parentWriter->setLastParagraphStyle(); - } - - return $content; - } - - /** - * Write font style beginning - * - * @param \PhpOffice\PhpWord\Style\Font $style - * @return string - */ - private function writeFontStyleBegin($style) - { - if (!$style instanceof FontStyle) { + /** @var \PhpOffice\PhpWord\Element\Text $element Type hint */ + $element = $this->element; + $elementClass = str_replace('\\Writer\\RTF', '', get_class($this)); + if (!$element instanceof $elementClass) { return ''; } - // Create style writer and set color/name index - $styleWriter = new FontStyleWriter($style); - if ($style->getColor() != null) { - $colorIndex = array_search($style->getColor(), $this->parentWriter->getColorTable()); - if ($colorIndex !== false) { - $styleWriter->setColorIndex($colorIndex + 1); - } - } - if ($style->getName() != null) { - $fontIndex = array_search($style->getName(), $this->parentWriter->getFontTable()); - if ($fontIndex !== false) { - $styleWriter->setNameIndex($fontIndex + 1); - } - } + $this->getStyles(); - // Write style - $content = $styleWriter->write(); + $content = ''; + $content .= $this->writeOpening(); + $content .= '{'; + $content .= $this->writeFontStyle(); + $content .= $this->writeText($element->getText()); + $content .= '}'; + $content .= $this->writeClosing(); return $content; } - - /** - * Write font style ending - * - * @param \PhpOffice\PhpWord\Style\Font $style - * @return string - */ - private function writeFontStyleEnd($style) - { - if (!$style instanceof FontStyle) { - return ''; - } - - $styleWriter = new FontStyleWriter($style); - $content = $styleWriter->writeEnd(); - - return $content; - } - - /** - * Get font style - * - * @return \PhpOffice\PhpWord\Style\Font - */ - private function getFontStyle() - { - $fontStyle = $this->element->getFontStyle(); - if (is_string($fontStyle)) { - $fontStyle = Style::getStyle($fontStyle); - } - - return $fontStyle; - } } diff --git a/src/PhpWord/Writer/RTF/Element/TextBreak.php b/src/PhpWord/Writer/RTF/Element/TextBreak.php index 760f34e8..4449be65 100644 --- a/src/PhpWord/Writer/RTF/Element/TextBreak.php +++ b/src/PhpWord/Writer/RTF/Element/TextBreak.php @@ -31,7 +31,9 @@ class TextBreak extends AbstractElement */ public function write() { - $this->parentWriter->setLastParagraphStyle(); + /** @var \PhpOffice\PhpWord\Writer\RTF $parentWriter Type hint */ + $parentWriter = $this->parentWriter; + $parentWriter->setLastParagraphStyle(); return '\par' . PHP_EOL; } diff --git a/src/PhpWord/Writer/RTF/Element/TextRun.php b/src/PhpWord/Writer/RTF/Element/TextRun.php index 174aebd9..e7563716 100644 --- a/src/PhpWord/Writer/RTF/Element/TextRun.php +++ b/src/PhpWord/Writer/RTF/Element/TextRun.php @@ -17,8 +17,6 @@ namespace PhpOffice\PhpWord\Writer\RTF\Element; -use PhpOffice\PhpWord\Writer\RTF\Element\Container; - /** * TextRun element RTF writer * @@ -33,12 +31,14 @@ class TextRun extends AbstractElement */ public function write() { - $content = ''; - - $content .= '\pard\nowidctlpar' . PHP_EOL; $writer = new Container($this->parentWriter, $this->element); + + $content = ''; + $content .= $this->writeOpening(); + $content .= '{'; $content .= $writer->write(); - $content .= '\par' . PHP_EOL; + $content .= '}'; + $content .= $this->writeClosing(); return $content; } diff --git a/src/PhpWord/Writer/RTF/Element/Title.php b/src/PhpWord/Writer/RTF/Element/Title.php index d78bb6f4..b9645a68 100644 --- a/src/PhpWord/Writer/RTF/Element/Title.php +++ b/src/PhpWord/Writer/RTF/Element/Title.php @@ -18,29 +18,10 @@ namespace PhpOffice\PhpWord\Writer\RTF\Element; /** - * TextBreak element RTF writer + * Title element RTF writer; extends from text * - * @since 0.10.0 + * @since 0.11.0 */ -class Title extends AbstractElement +class Title extends Text { - /** - * Write element - * - * @return string - */ - public function write() - { - if (!$this->element instanceof \PhpOffice\PhpWord\Element\Title) { - return; - } - - $content = ''; - - $content .= '\pard\nowidctlpar' . PHP_EOL; - $content .= $this->element->getText(); - $content .= '\par' . PHP_EOL; - - return $content; - } } diff --git a/src/PhpWord/Writer/RTF/Style/AbstractStyle.php b/src/PhpWord/Writer/RTF/Style/AbstractStyle.php index 55d6588e..7b55fdc2 100644 --- a/src/PhpWord/Writer/RTF/Style/AbstractStyle.php +++ b/src/PhpWord/Writer/RTF/Style/AbstractStyle.php @@ -17,13 +17,13 @@ namespace PhpOffice\PhpWord\Writer\RTF\Style; -use PhpOffice\PhpWord\Style\AbstractStyle as Style; +use PhpOffice\PhpWord\Writer\HTML\Style\AbstractStyle as HTMLAbstractStyle; /** * Abstract RTF style writer * * @since 0.11.0 */ -abstract class AbstractStyle extends \PhpOffice\PhpWord\Writer\HTML\Style\AbstractStyle +abstract class AbstractStyle extends HTMLAbstractStyle { } diff --git a/src/PhpWord/Writer/RTF/Style/Font.php b/src/PhpWord/Writer/RTF/Style/Font.php index 5c14eb3a..9634b566 100644 --- a/src/PhpWord/Writer/RTF/Style/Font.php +++ b/src/PhpWord/Writer/RTF/Style/Font.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWord\Writer\RTF\Style; -use PhpOffice\PhpWord\PhpWord; +use PhpOffice\PhpWord\Style\Font as FontStyle; /** * RTF font style writer @@ -44,40 +44,25 @@ class Font extends AbstractStyle public function write() { $style = $this->getStyle(); - if (!$style instanceof \PhpOffice\PhpWord\Style\Font) { - return; + if (!$style instanceof FontStyle) { + return ''; } $content = ''; $content .= '\cf' . $this->colorIndex; $content .= '\f' . $this->nameIndex; + + $size = $style->getSize(); + $content .= $this->getValueIf(is_numeric($size), '\fs' . ($size * 2)); + $content .= $this->getValueIf($style->isBold(), '\b'); $content .= $this->getValueIf($style->isItalic(), '\i'); - $content .= $this->getValueIf($style->getSize(), '\fs' . ($style->getSize() * 2)); + $content .= $this->getValueIf($style->getUnderline() != FontStyle::UNDERLINE_NONE, '\ul'); + $content .= $this->getValueIf($style->isStrikethrough(), '\strike'); + $content .= $this->getValueIf($style->isSuperScript(), '\super'); + $content .= $this->getValueIf($style->isSubScript(), '\sub'); - return $content; - } - - /** - * Write end style - * - * @return string - */ - public function writeEnd() - { - $style = $this->getStyle(); - if (!$style instanceof \PhpOffice\PhpWord\Style\Font) { - return; - } - - $content = ''; - $content .= '\cf0'; - $content .= '\f0'; - $content .= $this->getValueIf($style->isBold(), '\b0'); - $content .= $this->getValueIf($style->isItalic(), '\i0'); - $content .= $this->getValueIf($style->getSize(), '\fs' . (PhpWord::DEFAULT_FONT_SIZE * 2)); - - return $content; + return $content . ' '; } /** diff --git a/src/PhpWord/Writer/RTF/Style/Paragraph.php b/src/PhpWord/Writer/RTF/Style/Paragraph.php index 512e5774..e5f5d85e 100644 --- a/src/PhpWord/Writer/RTF/Style/Paragraph.php +++ b/src/PhpWord/Writer/RTF/Style/Paragraph.php @@ -17,6 +17,8 @@ namespace PhpOffice\PhpWord\Writer\RTF\Style; +use PhpOffice\PhpWord\Style\Alignment; + /** * RTF paragraph style writer * @@ -33,18 +35,26 @@ class Paragraph extends AbstractStyle { $style = $this->getStyle(); if (!$style instanceof \PhpOffice\PhpWord\Style\Paragraph) { - return; + return ''; } - $content = '\pard\nowidctlpar'; + $alignments = array( + Alignment::ALIGN_LEFT => '\ql', + Alignment::ALIGN_RIGHT => '\qr', + Alignment::ALIGN_CENTER => '\qc', + Alignment::ALIGN_BOTH => '\qj', + ); - // Alignment $align = $style->getAlign(); - $content .= $this->getValueIf(!is_null($align) && $align == 'center', '\qc'); - - // Spacing $spaceAfter = $style->getSpaceAfter(); - $content .= $this->getValueIf(!is_null($spaceAfter), '\sa' . $spaceAfter); + $spaceBefore = $style->getSpaceBefore(); + + $content = '\pard\nowidctlpar'; + if (isset($alignments[$align])) { + $content .= $alignments[$align]; + } + $content .= $this->getValueIf($spaceBefore !== null, '\sb' . $spaceBefore); + $content .= $this->getValueIf($spaceAfter !== null, '\sa' . $spaceAfter); return $content; } diff --git a/src/PhpWord/Writer/Word2007.php b/src/PhpWord/Writer/Word2007.php index 44317bd2..7d3c73bc 100644 --- a/src/PhpWord/Writer/Word2007.php +++ b/src/PhpWord/Writer/Word2007.php @@ -18,9 +18,9 @@ namespace PhpOffice\PhpWord\Writer; use PhpOffice\PhpWord\Element\Section; -use PhpOffice\PhpWord\Exception\Exception; use PhpOffice\PhpWord\Media; use PhpOffice\PhpWord\PhpWord; +use PhpOffice\PhpWord\Shared\ZipArchive; /** * Word2007 writer @@ -74,9 +74,10 @@ class Word2007 extends AbstractWriter implements WriterInterface foreach (array_keys($this->parts) as $partName) { $partClass = get_class($this) . '\\Part\\' . $partName; if (class_exists($partClass)) { - $partObject = new $partClass(); - $partObject->setParentWriter($this); - $this->writerParts[strtolower($partName)] = $partObject; + /** @var \PhpOffice\PhpWord\Writer\Word2007\Part\AbstractPart $part Type hint */ + $part = new $partClass(); + $part->setParentWriter($this); + $this->writerParts[strtolower($partName)] = $part; } } @@ -91,12 +92,9 @@ class Word2007 extends AbstractWriter implements WriterInterface */ public function save($filename = null) { - if (is_null($this->phpWord)) { - throw new Exception('PhpWord object unassigned.'); - } - $filename = $this->getTempFile($filename); - $objZip = $this->getZipArchive($filename); + $zip = $this->getZipArchive($filename); + $phpWord = $this->getPhpWord(); // Content types $this->contentTypes['default'] = array( @@ -107,7 +105,7 @@ class Word2007 extends AbstractWriter implements WriterInterface // Add section media files $sectionMedia = Media::getElements('section'); if (!empty($sectionMedia)) { - $this->addFilesToPackage($objZip, $sectionMedia); + $this->addFilesToPackage($zip, $sectionMedia); $this->registerContentTypes($sectionMedia); foreach ($sectionMedia as $element) { $this->relationships[] = $element; @@ -115,32 +113,29 @@ class Word2007 extends AbstractWriter implements WriterInterface } // Add header/footer media files & relations - $this->addHeaderFooterMedia($objZip, 'header'); - $this->addHeaderFooterMedia($objZip, 'footer'); + $this->addHeaderFooterMedia($zip, 'header'); + $this->addHeaderFooterMedia($zip, 'footer'); // Add header/footer contents $rId = Media::countElements('section') + 6; // @see Rels::writeDocRels for 6 first elements - $sections = $this->phpWord->getSections(); + $sections = $phpWord->getSections(); foreach ($sections as $section) { - $this->addHeaderFooterContent($section, $objZip, 'header', $rId); - $this->addHeaderFooterContent($section, $objZip, 'footer', $rId); + $this->addHeaderFooterContent($section, $zip, 'header', $rId); + $this->addHeaderFooterContent($section, $zip, 'footer', $rId); } - $this->addNotes($objZip, $rId, 'footnote'); - $this->addNotes($objZip, $rId, 'endnote'); + $this->addNotes($zip, $rId, 'footnote'); + $this->addNotes($zip, $rId, 'endnote'); // Write parts foreach ($this->parts as $partName => $fileName) { if ($fileName != '') { - $objZip->addFromString($fileName, $this->getWriterPart($partName)->write()); + $zip->addFromString($fileName, $this->getWriterPart($partName)->write()); } } - // Close file - if ($objZip->close() === false) { - throw new Exception("Could not close zip file $filename."); - } - + // Close zip archive and cleanup temp file + $zip->close(); $this->cleanupTempFile(); } @@ -167,22 +162,23 @@ class Word2007 extends AbstractWriter implements WriterInterface /** * Add header/footer media files, e.g. footer1.xml.rels * - * @param mixed $objZip + * @param \PhpOffice\PhpWord\Shared\ZipArchive $zip * @param string $docPart */ - private function addHeaderFooterMedia($objZip, $docPart) + private function addHeaderFooterMedia(ZipArchive $zip, $docPart) { $elements = Media::getElements($docPart); if (!empty($elements)) { foreach ($elements as $file => $media) { if (count($media) > 0) { if (!empty($media)) { - $this->addFilesToPackage($objZip, $media); + $this->addFilesToPackage($zip, $media); $this->registerContentTypes($media); } + /** @var \PhpOffice\PhpWord\Writer\Word2007\Part\AbstractPart $writerPart Type hint */ $writerPart = $this->getWriterPart('relspart')->setMedia($media); - $objZip->addFromString("word/_rels/{$file}.xml.rels", $writerPart->write()); + $zip->addFromString("word/_rels/{$file}.xml.rels", $writerPart->write()); } } } @@ -191,58 +187,64 @@ class Word2007 extends AbstractWriter implements WriterInterface /** * Add header/footer content * - * @param mixed $objZip + * @param \PhpOffice\PhpWord\Element\Section $section + * @param \PhpOffice\PhpWord\Shared\ZipArchive $zip * @param string $elmType header|footer * @param integer $rId */ - private function addHeaderFooterContent(Section &$section, $objZip, $elmType, &$rId) + private function addHeaderFooterContent(Section &$section, ZipArchive $zip, $elmType, &$rId) { $getFunction = $elmType == 'header' ? 'getHeaders' : 'getFooters'; $elmCount = ($section->getSectionId() - 1) * 3; $elements = $section->$getFunction(); foreach ($elements as &$element) { + /** @var \PhpOffice\PhpWord\Element\AbstractElement $element Type hint */ $elmCount++; $element->setRelationId(++$rId); $elmFile = "{$elmType}{$elmCount}.xml"; // e.g. footer1.xml $this->contentTypes['override']["/word/$elmFile"] = $elmType; $this->relationships[] = array('target' => $elmFile, 'type' => $elmType, 'rID' => $rId); + /** @var \PhpOffice\PhpWord\Writer\Word2007\Part\AbstractPart $writerPart Type hint */ $writerPart = $this->getWriterPart($elmType)->setElement($element); - $objZip->addFromString("word/$elmFile", $writerPart->write()); + $zip->addFromString("word/$elmFile", $writerPart->write()); } } /** * Add footnotes/endnotes * - * @param mixed $objZip + * @param \PhpOffice\PhpWord\Shared\ZipArchive $zip * @param integer $rId * @param string $noteType */ - private function addNotes($objZip, &$rId, $noteType = 'footnote') + private function addNotes(ZipArchive $zip, &$rId, $noteType = 'footnote') { + $phpWord = $this->getPhpWord(); $noteType = ($noteType == 'endnote') ? 'endnote' : 'footnote'; $partName = "{$noteType}s"; $method = 'get' . $partName; - $collection = $this->phpWord->$method(); + $collection = $phpWord->$method(); // Add footnotes media files, relations, and contents + /** @var \PhpOffice\PhpWord\Collection\AbstractCollection $collection Type hint */ if ($collection->countItems() > 0) { $media = Media::getElements($noteType); - $this->addFilesToPackage($objZip, $media); + $this->addFilesToPackage($zip, $media); $this->registerContentTypes($media); $this->contentTypes['override']["/word/{$partName}.xml"] = $partName; $this->relationships[] = array('target' => "{$partName}.xml", 'type' => $partName, 'rID' => ++$rId); // Write relationships file, e.g. word/_rels/footnotes.xml if (!empty($media)) { + /** @var \PhpOffice\PhpWord\Writer\Word2007\Part\AbstractPart $writerPart Type hint */ $writerPart = $this->getWriterPart('relspart')->setMedia($media); - $objZip->addFromString("word/_rels/{$partName}.xml.rels", $writerPart->write()); + $zip->addFromString("word/_rels/{$partName}.xml.rels", $writerPart->write()); } // Write content file, e.g. word/footnotes.xml $writerPart = $this->getWriterPart($partName)->setElements($collection->getItems()); - $objZip->addFromString("word/{$partName}.xml", $writerPart->write()); + $zip->addFromString("word/{$partName}.xml", $writerPart->write()); } } diff --git a/src/PhpWord/Writer/Word2007/Element/AbstractElement.php b/src/PhpWord/Writer/Word2007/Element/AbstractElement.php index 4b38d01f..52b4c62e 100644 --- a/src/PhpWord/Writer/Word2007/Element/AbstractElement.php +++ b/src/PhpWord/Writer/Word2007/Element/AbstractElement.php @@ -18,7 +18,7 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Element; use PhpOffice\PhpWord\Element\AbstractElement as Element; -use PhpOffice\PhpWord\Exception\Exception; +use PhpOffice\PhpWord\Shared\String; use PhpOffice\PhpWord\Shared\XMLWriter; /** @@ -49,6 +49,13 @@ abstract class AbstractElement */ protected $withoutP = false; + /** + * Has page break before + * + * @var bool + */ + private $pageBreakBefore = false; + /** * Write element */ @@ -57,6 +64,8 @@ abstract class AbstractElement /** * Create new instance * + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Element\AbstractElement $element * @param bool $withoutP */ public function __construct(XMLWriter $xmlWriter, Element $element, $withoutP = false) @@ -77,16 +86,43 @@ abstract class AbstractElement } /** - * Get Element + * Get element * * @return \PhpOffice\PhpWord\Element\AbstractElement */ protected function getElement() { - if (!is_null($this->element)) { - return $this->element; - } else { - throw new Exception('No element assigned.'); - } + return $this->element; + } + + /** + * Has page break before + * + * @return bool + */ + public function hasPageBreakBefore() + { + return $this->pageBreakBefore; + } + + /** + * Set page break before + * + * @param bool $value + */ + public function setPageBreakBefore($value = true) + { + $this->pageBreakBefore = (bool)$value; + } + + /** + * Convert text to valid format + * + * @param string $text + * @return string + */ + protected function getText($text) + { + return String::controlCharacterPHP2OOXML(htmlspecialchars($text)); } } diff --git a/src/PhpWord/Writer/Word2007/Element/CheckBox.php b/src/PhpWord/Writer/Word2007/Element/CheckBox.php index 96e210b5..ea13b8f9 100644 --- a/src/PhpWord/Writer/Word2007/Element/CheckBox.php +++ b/src/PhpWord/Writer/Word2007/Element/CheckBox.php @@ -17,8 +17,6 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Element; -use PhpOffice\PhpWord\Shared\String; - /** * CheckBox element writer * @@ -33,11 +31,9 @@ class CheckBox extends Text { $xmlWriter = $this->getXmlWriter(); $element = $this->getElement(); - - $name = htmlspecialchars($element->getName()); - $name = String::controlCharacterPHP2OOXML($name); - $text = htmlspecialchars($element->getText()); - $text = String::controlCharacterPHP2OOXML($text); + if (!$element instanceof \PhpOffice\PhpWord\Element\CheckBox) { + return; + } $this->writeOpeningWP(); @@ -46,7 +42,7 @@ class CheckBox extends Text $xmlWriter->writeAttribute('w:fldCharType', 'begin'); $xmlWriter->startElement('w:ffData'); $xmlWriter->startElement('w:name'); - $xmlWriter->writeAttribute('w:val', $name); + $xmlWriter->writeAttribute('w:val', $this->getText($element->getName())); $xmlWriter->endElement(); //w:name $xmlWriter->writeAttribute('w:enabled', ''); $xmlWriter->startElement('w:calcOnExit'); @@ -85,10 +81,10 @@ class CheckBox extends Text $xmlWriter->startElement('w:t'); $xmlWriter->writeAttribute('xml:space', 'preserve'); - $xmlWriter->writeRaw($text); + $xmlWriter->writeRaw($this->getText($element->getText())); $xmlWriter->endElement(); // w:t $xmlWriter->endElement(); // w:r - $this->writeEndingWP(); + $this->writeClosingWP(); } } diff --git a/src/PhpWord/Writer/Word2007/Element/Container.php b/src/PhpWord/Writer/Word2007/Element/Container.php index 150cb324..7d1c8104 100644 --- a/src/PhpWord/Writer/Word2007/Element/Container.php +++ b/src/PhpWord/Writer/Word2007/Element/Container.php @@ -17,6 +17,7 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Element; +use PhpOffice\PhpWord\Element\AbstractContainer as ContainerElement; use PhpOffice\PhpWord\Element\TextBreak as TextBreakElement; /** @@ -38,29 +39,45 @@ class Container extends AbstractElement */ public function write() { - $xmlWriter = $this->getXmlWriter(); $container = $this->getElement(); + if (!$container instanceof ContainerElement) { + return; + } $containerClass = substr(get_class($container), strrpos(get_class($container), '\\') + 1); $withoutP = in_array($containerClass, array('TextRun', 'Footnote', 'Endnote', 'ListItemRun')) ? true : false; + $xmlWriter = $this->getXmlWriter(); // Loop through elements $elements = $container->getElements(); $elementClass = ''; - if (count($elements) > 0) { - foreach ($elements as $element) { - $elementClass = get_class($element); - $writerClass = str_replace('PhpOffice\\PhpWord\\Element', $this->namespace, $elementClass); - if (class_exists($writerClass)) { - $writer = new $writerClass($xmlWriter, $element, $withoutP); - $writer->write(); - } + foreach ($elements as $element) { + $elementClass = substr(get_class($element), strrpos(get_class($element), '\\') + 1); + $writerClass = $this->namespace . '\\' . $elementClass; + + // Check it's a page break. No need to write it, instead, flag containers' pageBreakBefore + // to be assigned to the next element + if ($elementClass == 'PageBreak') { + $this->setPageBreakBefore(true); + continue; + } + if (class_exists($writerClass)) { + // Get container's page break before and reset it + $pageBreakBefore = $this->hasPageBreakBefore(); + $this->setPageBreakBefore(false); + + /** @var \PhpOffice\PhpWord\Writer\Word2007\Element\AbstractElement $writer Type hint */ + $writer = new $writerClass($xmlWriter, $element, $withoutP); + $writer->setPageBreakBefore($pageBreakBefore); + $writer->write(); } } - // Special case for Cell: They have to contain a w:p element at the end + // Special case for Cell: They have to contain a w:p element at the end. The $elementClass contains + // the last element name. If it's empty string or Table, the last element is not w:p if ($containerClass == 'Cell') { - if ($elementClass == '' || $elementClass == 'PhpOffice\\PhpWord\\Element\\Table') { - $writerClass = "{$this->namespace}\\TextBreak"; + if ($elementClass == '' || $elementClass == 'Table') { + $writerClass = $this->namespace . '\\TextBreak'; + /** @var \PhpOffice\PhpWord\Writer\Word2007\Element\AbstractElement $writer Type hint */ $writer = new $writerClass($xmlWriter, new TextBreakElement(), $withoutP); $writer->write(); } diff --git a/src/PhpWord/Writer/Word2007/Element/Footnote.php b/src/PhpWord/Writer/Word2007/Element/Footnote.php index 646f70ed..240a8a00 100644 --- a/src/PhpWord/Writer/Word2007/Element/Footnote.php +++ b/src/PhpWord/Writer/Word2007/Element/Footnote.php @@ -38,6 +38,9 @@ class Footnote extends Text { $xmlWriter = $this->getXmlWriter(); $element = $this->getElement(); + if (!$element instanceof \PhpOffice\PhpWord\Element\Footnote) { + return; + } $this->writeOpeningWP(); @@ -52,6 +55,6 @@ class Footnote extends Text $xmlWriter->endElement(); // w:$referenceType $xmlWriter->endElement(); // w:r - $this->writeEndingWP(); + $this->writeClosingWP(); } } diff --git a/src/PhpWord/Writer/Word2007/Element/Image.php b/src/PhpWord/Writer/Word2007/Element/Image.php index c7bd8d7d..a882040e 100644 --- a/src/PhpWord/Writer/Word2007/Element/Image.php +++ b/src/PhpWord/Writer/Word2007/Element/Image.php @@ -17,6 +17,8 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Element; +use PhpOffice\PhpWord\Element\Image as ImageElement; +use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Writer\Word2007\Style\Image as ImageStyleWriter; /** @@ -31,38 +33,32 @@ class Image extends AbstractElement */ public function write() { + $xmlWriter = $this->getXmlWriter(); $element = $this->getElement(); + if (!$element instanceof ImageElement) { + return; + } if ($element->isWatermark()) { - $this->writeWatermark(); + $this->writeWatermark($xmlWriter, $element); } else { - $this->writeImage(); + $this->writeImage($xmlWriter, $element); } } /** * Write image element */ - private function writeImage() + private function writeImage(XMLWriter $xmlWriter, ImageElement $element) { - $xmlWriter = $this->getXmlWriter(); - $element = $this->getElement(); - $rId = $element->getRelationId() + ($element->isInSection() ? 6 : 0); $style = $element->getStyle(); $styleWriter = new ImageStyleWriter($xmlWriter, $style); if (!$this->withoutP) { $xmlWriter->startElement('w:p'); - if (!is_null($style->getAlign())) { - $xmlWriter->startElement('w:pPr'); - $xmlWriter->startElement('w:jc'); - $xmlWriter->writeAttribute('w:val', $style->getAlign()); - $xmlWriter->endElement(); // w:jc - $xmlWriter->endElement(); // w:pPr - } + $styleWriter->writeAlignment(); } - $xmlWriter->startElement('w:r'); $xmlWriter->startElement('w:pict'); $xmlWriter->startElement('v:shape'); @@ -84,11 +80,8 @@ class Image extends AbstractElement /** * Write watermark element */ - private function writeWatermark() + private function writeWatermark(XMLWriter $xmlWriter, ImageElement $element) { - $xmlWriter = $this->getXmlWriter(); - $element = $this->getElement(); - $rId = $element->getRelationId(); $style = $element->getStyle(); $style->setPositioning('absolute'); diff --git a/src/PhpWord/Writer/Word2007/Element/Link.php b/src/PhpWord/Writer/Word2007/Element/Link.php index 517e276d..ec531bac 100644 --- a/src/PhpWord/Writer/Word2007/Element/Link.php +++ b/src/PhpWord/Writer/Word2007/Element/Link.php @@ -31,6 +31,9 @@ class Link extends Text { $xmlWriter = $this->getXmlWriter(); $element = $this->getElement(); + if (!$element instanceof \PhpOffice\PhpWord\Element\Link) { + return; + } $rId = $element->getRelationId() + ($element->isInSection() ? 6 : 0); @@ -50,6 +53,6 @@ class Link extends Text $xmlWriter->endElement(); // w:r $xmlWriter->endElement(); // w:hyperlink - $this->writeEndingWP(); + $this->writeClosingWP(); } } diff --git a/src/PhpWord/Writer/Word2007/Element/ListItem.php b/src/PhpWord/Writer/Word2007/Element/ListItem.php index e625114c..7b86efae 100644 --- a/src/PhpWord/Writer/Word2007/Element/ListItem.php +++ b/src/PhpWord/Writer/Word2007/Element/ListItem.php @@ -33,6 +33,9 @@ class ListItem extends AbstractElement { $xmlWriter = $this->getXmlWriter(); $element = $this->getElement(); + if (!$element instanceof \PhpOffice\PhpWord\Element\ListItem) { + return; + } $textObject = $element->getTextObject(); diff --git a/src/PhpWord/Writer/Word2007/Element/ListItemRun.php b/src/PhpWord/Writer/Word2007/Element/ListItemRun.php index 4431ffe6..747c2625 100644 --- a/src/PhpWord/Writer/Word2007/Element/ListItemRun.php +++ b/src/PhpWord/Writer/Word2007/Element/ListItemRun.php @@ -33,6 +33,9 @@ class ListItemRun extends AbstractElement { $xmlWriter = $this->getXmlWriter(); $element = $this->getElement(); + if (!$element instanceof \PhpOffice\PhpWord\Element\ListItemRun) { + return; + } $xmlWriter->startElement('w:p'); diff --git a/src/PhpWord/Writer/Word2007/Element/Object.php b/src/PhpWord/Writer/Word2007/Element/Object.php index 5f56a704..ae03f04f 100644 --- a/src/PhpWord/Writer/Word2007/Element/Object.php +++ b/src/PhpWord/Writer/Word2007/Element/Object.php @@ -17,6 +17,8 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Element; +use PhpOffice\PhpWord\Writer\Word2007\Style\Image as ImageStyleWriter; + /** * Object element writer * @@ -31,23 +33,20 @@ class Object extends AbstractElement { $xmlWriter = $this->getXmlWriter(); $element = $this->getElement(); + if (!$element instanceof \PhpOffice\PhpWord\Element\Object) { + return; + } $rIdObject = $element->getRelationId() + ($element->isInSection() ? 6 : 0); $rIdImage = $element->getImageRelationId() + ($element->isInSection() ? 6 : 0); $shapeId = md5($rIdObject . '_' . $rIdImage); $objectId = $element->getRelationId() + 1325353440; $style = $element->getStyle(); - $align = $style->getAlign(); + $styleWriter = new ImageStyleWriter($xmlWriter, $style); if (!$this->withoutP) { $xmlWriter->startElement('w:p'); - } - if (!is_null($align)) { - $xmlWriter->startElement('w:pPr'); - $xmlWriter->startElement('w:jc'); - $xmlWriter->writeAttribute('w:val', $align); - $xmlWriter->endElement(); - $xmlWriter->endElement(); + $styleWriter->writeAlignment(); } $xmlWriter->startElement('w:r'); $xmlWriter->startElement('w:object'); diff --git a/src/PhpWord/Writer/Word2007/Element/PageBreak.php b/src/PhpWord/Writer/Word2007/Element/PageBreak.php index fb285ac6..6974777a 100644 --- a/src/PhpWord/Writer/Word2007/Element/PageBreak.php +++ b/src/PhpWord/Writer/Word2007/Element/PageBreak.php @@ -20,23 +20,27 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Element; /** * PageBreak element writer * + * Originally, page break is rendered as a `w:p`, but this turns out to produce bug #150. + * As of 0.11.0, page break is rendered as a `w:r` with `w:br` type "page" and `w:lastRenderedPageBreak` + * * @since 0.10.0 */ class PageBreak extends AbstractElement { /** * Write element + * + * @usedby \PhpOffice\PhpWord\Writer\Word2007\Element\Text::writeOpeningWP() */ public function write() { $xmlWriter = $this->getXmlWriter(); - $xmlWriter->startElement('w:p'); $xmlWriter->startElement('w:r'); $xmlWriter->startElement('w:br'); $xmlWriter->writeAttribute('w:type', 'page'); - $xmlWriter->endElement(); - $xmlWriter->endElement(); - $xmlWriter->endElement(); + $xmlWriter->endElement(); // w:br + $xmlWriter->writeElement('w:lastRenderedPageBreak'); + $xmlWriter->endElement(); // w:r } } diff --git a/src/PhpWord/Writer/Word2007/Element/PreserveText.php b/src/PhpWord/Writer/Word2007/Element/PreserveText.php index b3b00d16..dd5d9008 100644 --- a/src/PhpWord/Writer/Word2007/Element/PreserveText.php +++ b/src/PhpWord/Writer/Word2007/Element/PreserveText.php @@ -17,8 +17,6 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Element; -use PhpOffice\PhpWord\Shared\String; - /** * PreserveText element writer * @@ -33,6 +31,9 @@ class PreserveText extends Text { $xmlWriter = $this->getXmlWriter(); $element = $this->getElement(); + if (!$element instanceof \PhpOffice\PhpWord\Element\PreserveText) { + return; + } $texts = $element->getText(); if (!is_array($texts)) { @@ -73,21 +74,18 @@ class PreserveText extends Text $xmlWriter->endElement(); $xmlWriter->endElement(); } else { - $text = htmlspecialchars($text); - $text = String::controlCharacterPHP2OOXML($text); - $xmlWriter->startElement('w:r'); $this->writeFontStyle(); $xmlWriter->startElement('w:t'); $xmlWriter->writeAttribute('xml:space', 'preserve'); - $xmlWriter->writeRaw($text); + $xmlWriter->writeRaw($this->getText($text)); $xmlWriter->endElement(); $xmlWriter->endElement(); } } - $this->writeEndingWP(); + $this->writeClosingWP(); } } diff --git a/src/PhpWord/Writer/Word2007/Element/TOC.php b/src/PhpWord/Writer/Word2007/Element/TOC.php index 28d7bc31..36ef4866 100644 --- a/src/PhpWord/Writer/Word2007/Element/TOC.php +++ b/src/PhpWord/Writer/Word2007/Element/TOC.php @@ -17,6 +17,8 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Element; +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; @@ -36,12 +38,15 @@ class TOC extends AbstractElement { $xmlWriter = $this->getXmlWriter(); $element = $this->getElement(); + if (!$element instanceof TOCElement) { + return; + } $titles = $element->getTitles(); $writeFieldMark = true; foreach ($titles as $title) { - $this->writeTitle($title, $writeFieldMark); + $this->writeTitle($xmlWriter, $element, $title, $writeFieldMark); if ($writeFieldMark) { $writeFieldMark = false; } @@ -59,26 +64,25 @@ class TOC extends AbstractElement /** * Write title * + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Element\TOC $element * @param \PhpOffice\PhpWord\Element\Title $title * @param bool $writeFieldMark */ - private function writeTitle($title, $writeFieldMark) + private function writeTitle(XMLWriter $xmlWriter, TOCElement $element, $title, $writeFieldMark) { - $xmlWriter = $this->getXmlWriter(); - $element = $this->getElement(); - $tocStyle = $element->getStyleTOC(); $fontStyle = $element->getStyleFont(); $isObject = ($fontStyle instanceof Font) ? true : false; - $anchor = '_Toc' . ($title->getBookmarkId() + 252634154); + $anchor = '_Toc' . ($title->getRelationId() + 252634154); $indent = ($title->getDepth() - 1) * $tocStyle->getIndent(); $xmlWriter->startElement('w:p'); // Write style and field mark - $this->writeStyle($indent); + $this->writeStyle($xmlWriter, $element, $indent); if ($writeFieldMark) { - $this->writeFieldMark(); + $this->writeFieldMark($xmlWriter, $element); } // Hyperlink @@ -128,13 +132,12 @@ class TOC extends AbstractElement /** * Write style * + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Element\TOC $element * @param int $indent */ - private function writeStyle($indent) + private function writeStyle(XMLWriter $xmlWriter, TOCElement $element, $indent) { - $xmlWriter = $this->getXmlWriter(); - $element = $this->getElement(); - $tocStyle = $element->getStyleTOC(); $fontStyle = $element->getStyleFont(); $isObject = ($fontStyle instanceof Font) ? true : false; @@ -142,8 +145,8 @@ class TOC extends AbstractElement $xmlWriter->startElement('w:pPr'); // Paragraph - if ($isObject && !is_null($fontStyle->getParagraphStyle())) { - $styleWriter = new ParagraphStyleWriter($xmlWriter, $fontStyle->getParagraphStyle()); + if ($isObject && !is_null($fontStyle->getParagraph())) { + $styleWriter = new ParagraphStyleWriter($xmlWriter, $fontStyle->getParagraph()); $styleWriter->write(); } @@ -175,11 +178,8 @@ class TOC extends AbstractElement /** * Write TOC Field */ - private function writeFieldMark() + private function writeFieldMark(XMLWriter $xmlWriter, TOCElement $element) { - $xmlWriter = $this->getXmlWriter(); - $element = $this->getElement(); - $minDepth = $element->getMinDepth(); $maxDepth = $element->getMaxDepth(); diff --git a/src/PhpWord/Writer/Word2007/Element/Table.php b/src/PhpWord/Writer/Word2007/Element/Table.php index 5c82114a..8cadfc38 100644 --- a/src/PhpWord/Writer/Word2007/Element/Table.php +++ b/src/PhpWord/Writer/Word2007/Element/Table.php @@ -19,9 +19,12 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Element; 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\Table as TableStyle; +use PhpOffice\PhpWord\Style\Row as RowStyle; use PhpOffice\PhpWord\Writer\Word2007\Style\Cell as CellStyleWriter; +use PhpOffice\PhpWord\Writer\Word2007\Style\Row as RowStyleWriter; use PhpOffice\PhpWord\Writer\Word2007\Style\Table as TableStyleWriter; /** @@ -38,6 +41,9 @@ class Table extends AbstractElement { $xmlWriter = $this->getXmlWriter(); $element = $this->getElement(); + if (!$element instanceof TableElement) { + return; + } $rows = $element->getRows(); $rowCount = count($rows); @@ -45,119 +51,96 @@ class Table extends AbstractElement if ($rowCount > 0) { $xmlWriter->startElement('w:tbl'); - // Table grid + // Write columns + $this->writeColumns($xmlWriter, $element); + + // Write style + $styleWriter = new TableStyleWriter($xmlWriter, $element->getStyle()); + $styleWriter->setWidth($element->getWidth()); + $styleWriter->write(); + + // Write rows + for ($i = 0; $i < $rowCount; $i++) { + $this->writeRow($xmlWriter, $rows[$i]); + } + + $xmlWriter->endElement(); // w:tbl + } + } + + /** + * Write column + */ + private function writeColumns(XMLWriter $xmlWriter, TableElement $element) + { + $rows = $element->getRows(); + $rowCount = count($rows); + + $cellWidths = array(); + for ($i = 0; $i < $rowCount; $i++) { + $row = $rows[$i]; + $cells = $row->getCells(); + if (count($cells) <= count($cellWidths)) { + continue; + } $cellWidths = array(); - for ($i = 0; $i < $rowCount; $i++) { - $row = $rows[$i]; - $cells = $row->getCells(); - if (count($cells) <= count($cellWidths)) { - continue; - } - $cellWidths = array(); - foreach ($cells as $cell) { - $cellWidths[] = $cell->getWidth(); - } + foreach ($cells as $cell) { + $cellWidths[] = $cell->getWidth(); } - $xmlWriter->startElement('w:tblGrid'); - foreach ($cellWidths as $width) { - $xmlWriter->startElement('w:gridCol'); - if (!is_null($width)) { - $xmlWriter->writeAttribute('w:w', $width); - $xmlWriter->writeAttribute('w:type', 'dxa'); - } - $xmlWriter->endElement(); - } - $xmlWriter->endElement(); // w:tblGrid + } - // Table style - $tblStyle = $element->getStyle(); - $tblWidth = $element->getWidth(); - if ($tblStyle instanceof TableStyle) { - $styleWriter = new TableStyleWriter($xmlWriter, $tblStyle); - $styleWriter->setIsFullStyle(false); - $styleWriter->write(); - } else { - if (!empty($tblStyle)) { - $xmlWriter->startElement('w:tblPr'); - $xmlWriter->startElement('w:tblStyle'); - $xmlWriter->writeAttribute('w:val', $tblStyle); - $xmlWriter->endElement(); - if (!is_null($tblWidth)) { - $xmlWriter->startElement('w:tblW'); - $xmlWriter->writeAttribute('w:w', $tblWidth); - $xmlWriter->writeAttribute('w:type', 'pct'); - $xmlWriter->endElement(); - } - $xmlWriter->endElement(); - } - } - - // Table rows - for ($i = 0; $i < $rowCount; $i++) { - $this->writeRow($rows[$i]); + $xmlWriter->startElement('w:tblGrid'); + foreach ($cellWidths as $width) { + $xmlWriter->startElement('w:gridCol'); + if ($width !== null) { + $xmlWriter->writeAttribute('w:w', $width); + $xmlWriter->writeAttribute('w:type', 'dxa'); } $xmlWriter->endElement(); } + $xmlWriter->endElement(); // w:tblGrid } /** * Write row */ - private function writeRow(RowElement $row) + private function writeRow(XMLWriter $xmlWriter, RowElement $row) { - $xmlWriter = $this->getXmlWriter(); - - $height = $row->getHeight(); - $rowStyle = $row->getStyle(); - $xmlWriter->startElement('w:tr'); - if (!is_null($height) || $rowStyle->isTblHeader() || $rowStyle->isCantSplit()) { - $xmlWriter->startElement('w:trPr'); - if (!is_null($height)) { - $xmlWriter->startElement('w:trHeight'); - $xmlWriter->writeAttribute('w:val', $height); - $xmlWriter->writeAttribute('w:hRule', ($rowStyle->isExactHeight() ? 'exact' : 'atLeast')); - $xmlWriter->endElement(); - } - if ($rowStyle->isTblHeader()) { - $xmlWriter->startElement('w:tblHeader'); - $xmlWriter->writeAttribute('w:val', '1'); - $xmlWriter->endElement(); - } - if ($rowStyle->isCantSplit()) { - $xmlWriter->startElement('w:cantSplit'); - $xmlWriter->writeAttribute('w:val', '1'); - $xmlWriter->endElement(); - } - $xmlWriter->endElement(); + + // Write style + $rowStyle = $row->getStyle(); + if ($rowStyle instanceof RowStyle) { + $styleWriter = new RowStyleWriter($xmlWriter, $rowStyle); + $styleWriter->setHeight($row->getHeight()); + $styleWriter->write(); } + + // Write cells foreach ($row->getCells() as $cell) { - $this->writeCell($cell); + $this->writeCell($xmlWriter, $cell); } + $xmlWriter->endElement(); // w:tr } /** * Write cell */ - private function writeCell(CellElement $cell) + private function writeCell(XMLWriter $xmlWriter, CellElement $cell) { - $xmlWriter = $this->getXmlWriter(); - - $cellStyle = $cell->getStyle(); $xmlWriter->startElement('w:tc'); - $xmlWriter->startElement('w:tcPr'); - $xmlWriter->startElement('w:tcW'); - $xmlWriter->writeAttribute('w:w', $cell->getWidth()); - $xmlWriter->writeAttribute('w:type', 'dxa'); - $xmlWriter->endElement(); // w:tcW + + // Write style + $cellStyle = $cell->getStyle(); if ($cellStyle instanceof CellStyle) { $styleWriter = new CellStyleWriter($xmlWriter, $cellStyle); + $styleWriter->setWidth($cell->getWidth()); $styleWriter->write(); } - $xmlWriter->endElement(); // w:tcPr + // Write content $containerWriter = new Container($xmlWriter, $cell); $containerWriter->write(); diff --git a/src/PhpWord/Writer/Word2007/Element/Text.php b/src/PhpWord/Writer/Word2007/Element/Text.php index d6402dbf..64c4b766 100644 --- a/src/PhpWord/Writer/Word2007/Element/Text.php +++ b/src/PhpWord/Writer/Word2007/Element/Text.php @@ -17,7 +17,7 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Element; -use PhpOffice\PhpWord\Shared\String; +use PhpOffice\PhpWord\Element\PageBreak as PageBreakElement; use PhpOffice\PhpWord\Writer\Word2007\Style\Font as FontStyleWriter; use PhpOffice\PhpWord\Writer\Word2007\Style\Paragraph as ParagraphStyleWriter; @@ -35,9 +35,9 @@ class Text extends AbstractElement { $xmlWriter = $this->getXmlWriter(); $element = $this->getElement(); - - $text = htmlspecialchars($element->getText()); - $text = String::controlCharacterPHP2OOXML($text); + if (!$element instanceof \PhpOffice\PhpWord\Element\Text) { + return; + } $this->writeOpeningWP(); @@ -47,15 +47,17 @@ class Text extends AbstractElement $xmlWriter->startElement('w:t'); $xmlWriter->writeAttribute('xml:space', 'preserve'); - $xmlWriter->writeRaw($text); + $xmlWriter->writeRaw($this->getText($element->getText())); $xmlWriter->endElement(); $xmlWriter->endElement(); // w:r - $this->writeEndingWP(); + $this->writeClosingWP(); } /** * Write opening + * + * @uses \PhpOffice\PhpWord\Writer\Word2007\Element\PageBreak::write() */ protected function writeOpeningWP() { @@ -64,17 +66,22 @@ class Text extends AbstractElement if (!$this->withoutP) { $xmlWriter->startElement('w:p'); - + // Paragraph style if (method_exists($element, 'getParagraphStyle')) { $this->writeParagraphStyle(); } + // PageBreak + if ($this->hasPageBreakBefore()) { + $elementWriter = new PageBreak($xmlWriter, new PageBreakElement()); + $elementWriter->write(); + } } } /** * Write ending */ - protected function writeEndingWP() + protected function writeClosingWP() { $xmlWriter = $this->getXmlWriter(); @@ -89,8 +96,9 @@ class Text extends AbstractElement protected function writeParagraphStyle() { $xmlWriter = $this->getXmlWriter(); - $element = $this->getElement(); + /** @var \PhpOffice\PhpWord\Element\Text $element Type hint */ + $element = $this->getElement(); $paragraphStyle = $element->getParagraphStyle(); $styleWriter = new ParagraphStyleWriter($xmlWriter, $paragraphStyle); $styleWriter->setIsInline(true); @@ -103,8 +111,9 @@ class Text extends AbstractElement protected function writeFontStyle() { $xmlWriter = $this->getXmlWriter(); - $element = $this->getElement(); + /** @var \PhpOffice\PhpWord\Element\Text $element Type hint */ + $element = $this->getElement(); $fontStyle = $element->getFontStyle(); $styleWriter = new FontStyleWriter($xmlWriter, $fontStyle); $styleWriter->setIsInline(true); diff --git a/src/PhpWord/Writer/Word2007/Element/TextBox.php b/src/PhpWord/Writer/Word2007/Element/TextBox.php index 6b63c31a..4ee5e68e 100644 --- a/src/PhpWord/Writer/Word2007/Element/TextBox.php +++ b/src/PhpWord/Writer/Word2007/Element/TextBox.php @@ -33,18 +33,15 @@ class TextBox extends AbstractElement { $xmlWriter = $this->getXmlWriter(); $element = $this->getElement(); + if (!$element instanceof \PhpOffice\PhpWord\Element\TextBox) { + return; + } $style = $element->getStyle(); $styleWriter = new TextBoxStyleWriter($xmlWriter, $style); if (!$this->withoutP) { $xmlWriter->startElement('w:p'); - if (!is_null($style->getAlign())) { - $xmlWriter->startElement('w:pPr'); - $xmlWriter->startElement('w:jc'); - $xmlWriter->writeAttribute('w:val', $style->getAlign()); - $xmlWriter->endElement(); // w:jc - $xmlWriter->endElement(); // w:pPr - } + $styleWriter->writeAlignment(); } $xmlWriter->startElement('w:r'); diff --git a/src/PhpWord/Writer/Word2007/Element/TextBreak.php b/src/PhpWord/Writer/Word2007/Element/TextBreak.php index 05de2917..227b1b30 100644 --- a/src/PhpWord/Writer/Word2007/Element/TextBreak.php +++ b/src/PhpWord/Writer/Word2007/Element/TextBreak.php @@ -31,6 +31,9 @@ class TextBreak extends Text { $xmlWriter = $this->getXmlWriter(); $element = $this->getElement(); + if (!$element instanceof \PhpOffice\PhpWord\Element\TextBreak) { + return; + } if (!$this->withoutP) { $hasStyle = $element->hasStyle(); @@ -39,7 +42,7 @@ class TextBreak extends Text $xmlWriter->startElement('w:pPr'); $this->writeFontStyle(); $xmlWriter->endElement(); // w:pPr - $this->writeEndingWP(); + $this->writeClosingWP(); } else { $xmlWriter->writeElement('w:p'); } diff --git a/src/PhpWord/Writer/Word2007/Element/TextRun.php b/src/PhpWord/Writer/Word2007/Element/TextRun.php index cb72ab18..330e297c 100644 --- a/src/PhpWord/Writer/Word2007/Element/TextRun.php +++ b/src/PhpWord/Writer/Word2007/Element/TextRun.php @@ -37,6 +37,6 @@ class TextRun extends Text $containerWriter = new Container($xmlWriter, $element); $containerWriter->write(); - $this->writeEndingWP(); + $this->writeClosingWP(); } } diff --git a/src/PhpWord/Writer/Word2007/Element/Title.php b/src/PhpWord/Writer/Word2007/Element/Title.php index c5eda5fd..298bd9b1 100644 --- a/src/PhpWord/Writer/Word2007/Element/Title.php +++ b/src/PhpWord/Writer/Word2007/Element/Title.php @@ -17,8 +17,6 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Element; -use PhpOffice\PhpWord\Shared\String; - /** * TextRun element writer * @@ -33,14 +31,14 @@ class Title extends AbstractElement { $xmlWriter = $this->getXmlWriter(); $element = $this->getElement(); + if (!$element instanceof \PhpOffice\PhpWord\Element\Title) { + return; + } - $bookmarkId = $element->getBookmarkId(); - $anchor = '_Toc' . ($bookmarkId + 252634154); + $rId = $element->getRelationId(); + $anchor = '_Toc' . ($rId + 252634154); $style = $element->getStyle(); - $text = htmlspecialchars($element->getText()); - $text = String::controlCharacterPHP2OOXML($text); - $xmlWriter->startElement('w:p'); if (!empty($style)) { @@ -58,18 +56,18 @@ class Title extends AbstractElement $xmlWriter->endElement(); $xmlWriter->startElement('w:bookmarkStart'); - $xmlWriter->writeAttribute('w:id', $bookmarkId); + $xmlWriter->writeAttribute('w:id', $rId); $xmlWriter->writeAttribute('w:name', $anchor); $xmlWriter->endElement(); $xmlWriter->startElement('w:r'); $xmlWriter->startElement('w:t'); - $xmlWriter->writeRaw($text); + $xmlWriter->writeRaw($this->getText($element->getText())); $xmlWriter->endElement(); $xmlWriter->endElement(); $xmlWriter->startElement('w:bookmarkEnd'); - $xmlWriter->writeAttribute('w:id', $bookmarkId); + $xmlWriter->writeAttribute('w:id', $rId); $xmlWriter->endElement(); $xmlWriter->endElement(); diff --git a/src/PhpWord/Writer/Word2007/Part/AbstractPart.php b/src/PhpWord/Writer/Word2007/Part/AbstractPart.php index b0454956..fbd4a6e5 100644 --- a/src/PhpWord/Writer/Word2007/Part/AbstractPart.php +++ b/src/PhpWord/Writer/Word2007/Part/AbstractPart.php @@ -19,7 +19,7 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Part; use PhpOffice\PhpWord\Exception\Exception; use PhpOffice\PhpWord\Shared\XMLWriter; -use PhpOffice\PhpWord\Writer\WriterInterface; +use PhpOffice\PhpWord\Writer\AbstractWriter; /** * Word2007 writer part abstract class @@ -29,16 +29,23 @@ abstract class AbstractPart /** * Parent writer * - * @var \PhpOffice\PhpWord\Writer\WriterInterface + * @var \PhpOffice\PhpWord\Writer\AbstractWriter */ protected $parentWriter; + /** + * Write part + * + * @return string + */ + abstract public function write(); + /** * Set parent writer * - * @param \PhpOffice\PhpWord\Writer\WriterInterface $writer + * @param \PhpOffice\PhpWord\Writer\AbstractWriter $writer */ - public function setParentWriter(WriterInterface $writer = null) + public function setParentWriter(AbstractWriter $writer = null) { $this->parentWriter = $writer; } @@ -46,7 +53,7 @@ abstract class AbstractPart /** * Get parent writer * - * @return \PhpOffice\PhpWord\Writer\WriterInterface + * @return \PhpOffice\PhpWord\Writer\AbstractWriter * @throws \PhpOffice\PhpWord\Exception\Exception */ public function getParentWriter() diff --git a/src/PhpWord/Writer/Word2007/Part/ContentTypes.php b/src/PhpWord/Writer/Word2007/Part/ContentTypes.php index 3af62a44..f8cb2f26 100644 --- a/src/PhpWord/Writer/Word2007/Part/ContentTypes.php +++ b/src/PhpWord/Writer/Word2007/Part/ContentTypes.php @@ -17,7 +17,6 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Part; -use PhpOffice\PhpWord\Exception\Exception; use PhpOffice\PhpWord\Shared\XMLWriter; /** @@ -32,7 +31,9 @@ class ContentTypes extends AbstractPart */ public function write() { - $contentTypes = $this->getParentWriter()->getContentTypes(); + /** @var \PhpOffice\PhpWord\Writer\Word2007 $parentWriter Type hint */ + $parentWriter = $this->getParentWriter(); + $contentTypes = $parentWriter->getContentTypes(); $openXMLPrefix = 'application/vnd.openxmlformats-'; $wordMLPrefix = $openXMLPrefix . 'officedocument.wordprocessingml.'; @@ -75,21 +76,16 @@ class ContentTypes extends AbstractPart * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter XML Writer * @param array $parts * @param boolean $isDefault - * @throws \PhpOffice\PhpWord\Exception\Exception */ private function writeContentType(XMLWriter $xmlWriter, $parts, $isDefault) { foreach ($parts as $partName => $contentType) { - if ($partName != '' && $contentType != '') { - $partType = $isDefault ? 'Default' : 'Override'; - $partAttribute = $isDefault ? 'Extension' : 'PartName'; - $xmlWriter->startElement($partType); - $xmlWriter->writeAttribute($partAttribute, $partName); - $xmlWriter->writeAttribute('ContentType', $contentType); - $xmlWriter->endElement(); - } else { - throw new Exception("Invalid parameters passed."); - } + $partType = $isDefault ? 'Default' : 'Override'; + $partAttribute = $isDefault ? 'Extension' : 'PartName'; + $xmlWriter->startElement($partType); + $xmlWriter->writeAttribute($partAttribute, $partName); + $xmlWriter->writeAttribute('ContentType', $contentType); + $xmlWriter->endElement(); } } } diff --git a/src/PhpWord/Writer/Word2007/Part/DocPropsApp.php b/src/PhpWord/Writer/Word2007/Part/DocPropsApp.php index 17d38a10..1e6549c5 100644 --- a/src/PhpWord/Writer/Word2007/Part/DocPropsApp.php +++ b/src/PhpWord/Writer/Word2007/Part/DocPropsApp.php @@ -17,8 +17,6 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Part; -use PhpOffice\PhpWord\PhpWord; - /** * Word2007 extended document properties part writer: docProps/app.xml * diff --git a/src/PhpWord/Writer/Word2007/Part/DocPropsCore.php b/src/PhpWord/Writer/Word2007/Part/DocPropsCore.php index 51400846..2b3bce5a 100644 --- a/src/PhpWord/Writer/Word2007/Part/DocPropsCore.php +++ b/src/PhpWord/Writer/Word2007/Part/DocPropsCore.php @@ -17,8 +17,6 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Part; -use PhpOffice\PhpWord\PhpWord; - /** * Word2007 core document properties part writer: docProps/core.xml * diff --git a/src/PhpWord/Writer/Word2007/Part/Document.php b/src/PhpWord/Writer/Word2007/Part/Document.php index 0f8a16af..99570338 100644 --- a/src/PhpWord/Writer/Word2007/Part/Document.php +++ b/src/PhpWord/Writer/Word2007/Part/Document.php @@ -18,7 +18,6 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Part; use PhpOffice\PhpWord\Element\Section; -use PhpOffice\PhpWord\PhpWord; use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Writer\Word2007\Element\Container; use PhpOffice\PhpWord\Writer\Word2007\Style\Section as SectionStyleWriter; diff --git a/src/PhpWord/Writer/Word2007/Part/FontTable.php b/src/PhpWord/Writer/Word2007/Part/FontTable.php index e894cd23..49a47e7d 100644 --- a/src/PhpWord/Writer/Word2007/Part/FontTable.php +++ b/src/PhpWord/Writer/Word2007/Part/FontTable.php @@ -20,6 +20,7 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Part; /** * Word2007 font table writer: word/fontTable.xml * + * @todo Generate content dynamically * @since 0.10.0 */ class FontTable extends AbstractPart @@ -29,7 +30,77 @@ class FontTable extends AbstractPart */ public function write() { - return ' -'; + $str = ''; + $str .= ''; + $str .= ''; + + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + + $str .= ''; + + return $str; } } diff --git a/src/PhpWord/Writer/Word2007/Part/Footnotes.php b/src/PhpWord/Writer/Word2007/Part/Footnotes.php index 1eeabc9c..903e5fe5 100644 --- a/src/PhpWord/Writer/Word2007/Part/Footnotes.php +++ b/src/PhpWord/Writer/Word2007/Part/Footnotes.php @@ -106,8 +106,9 @@ class Footnotes extends AbstractPart $xmlWriter->endElement(); // w:p $xmlWriter->endElement(); // $this->elementNode - // Content - foreach ($this->elements as $element) { + /** @var array $elements Type hint */ + $elements = $this->elements; + foreach ($elements as $element) { if ($element instanceof Footnote) { $this->writeNote($xmlWriter, $element); } diff --git a/src/PhpWord/Writer/Word2007/Part/Rels.php b/src/PhpWord/Writer/Word2007/Part/Rels.php index 44e62013..af57a768 100644 --- a/src/PhpWord/Writer/Word2007/Part/Rels.php +++ b/src/PhpWord/Writer/Word2007/Part/Rels.php @@ -97,6 +97,7 @@ class Rels extends AbstractPart * @param string $type Relationship type * @param string $target Relationship target * @param string $targetMode Relationship target mode + * @throws \PhpOffice\PhpWord\Exception\Exception */ private function writeRel(XMLWriter $xmlWriter, $relId, $type, $target, $targetMode = '') { diff --git a/src/PhpWord/Writer/Word2007/Part/RelsDocument.php b/src/PhpWord/Writer/Word2007/Part/RelsDocument.php index e0773a4a..744e14f9 100644 --- a/src/PhpWord/Writer/Word2007/Part/RelsDocument.php +++ b/src/PhpWord/Writer/Word2007/Part/RelsDocument.php @@ -40,7 +40,10 @@ class RelsDocument extends Rels 'fontTable.xml' => 'officeDocument/2006/relationships/fontTable', ); $xmlWriter = $this->getXmlWriter(); - $this->writeRels($xmlWriter, $xmlRels, $this->getParentWriter()->getRelationships()); + + /** @var \PhpOffice\PhpWord\Writer\Word2007 $parentWriter Type hint */ + $parentWriter = $this->getParentWriter(); + $this->writeRels($xmlWriter, $xmlRels, $parentWriter->getRelationships()); return $xmlWriter->getData(); } diff --git a/src/PhpWord/Writer/Word2007/Part/Settings.php b/src/PhpWord/Writer/Word2007/Part/Settings.php index 862e419e..784a5d1e 100644 --- a/src/PhpWord/Writer/Word2007/Part/Settings.php +++ b/src/PhpWord/Writer/Word2007/Part/Settings.php @@ -19,6 +19,8 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Part; /** * Word2007 settings part writer: word/settings.xml + * + * @link http://www.schemacentral.com/sc/ooxml/t-w_CT_Settings.html */ class Settings extends AbstractPart { @@ -126,6 +128,8 @@ class Settings extends AbstractPart $xmlWriter->writeElement($settingKey); } else { $xmlWriter->startElement($settingKey); + + /** @var array $settingValue Type hint */ foreach ($settingValue as $childKey => $childValue) { if ($childKey == '@attributes') { foreach ($childValue as $key => $val) { diff --git a/src/PhpWord/Writer/Word2007/Part/Styles.php b/src/PhpWord/Writer/Word2007/Part/Styles.php index 13e07e71..a0a6317a 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\PhpWord\PhpWord; +use PhpOffice\PhpWord\Settings as PhpWordSettings; use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Style; use PhpOffice\PhpWord\Style\Font; @@ -41,7 +41,6 @@ class Styles extends AbstractPart */ public function write() { - $phpWord = $this->getParentWriter()->getPhpWord(); $xmlWriter = $this->getXmlWriter(); $xmlWriter->startDocument('1.0', 'UTF-8', 'yes'); @@ -51,7 +50,7 @@ class Styles extends AbstractPart // Write default styles $styles = Style::getStyles(); - $this->writeDefaultStyles($xmlWriter, $phpWord, $styles); + $this->writeDefaultStyles($xmlWriter, $styles); // Write styles if (count($styles) > 0) { @@ -155,12 +154,12 @@ class Styles extends AbstractPart * Write default font and other default styles * * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter - * @param array $styles + * @param \PhpOffice\PhpWord\Style\AbstractStyle[] $styles */ - private function writeDefaultStyles(XMLWriter $xmlWriter, PhpWord $phpWord, $styles) + private function writeDefaultStyles(XMLWriter $xmlWriter, $styles) { - $fontName = $phpWord->getDefaultFontName(); - $fontSize = $phpWord->getDefaultFontSize(); + $fontName = PhpWordSettings::getDefaultFontName(); + $fontSize = PhpWordSettings::getDefaultFontSize(); // Default font $xmlWriter->startElement('w:docDefaults'); diff --git a/src/PhpWord/Writer/Word2007/Part/Theme.php b/src/PhpWord/Writer/Word2007/Part/Theme.php index 481b1d64..62911c54 100644 --- a/src/PhpWord/Writer/Word2007/Part/Theme.php +++ b/src/PhpWord/Writer/Word2007/Part/Theme.php @@ -20,6 +20,7 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Part; /** * Word2007 theme writer: word/theme/theme1.xml * + * @todo Generate content dynamically * @since 0.10.0 */ class Theme extends AbstractPart @@ -31,7 +32,392 @@ class Theme extends AbstractPart */ public function write() { - return ' -'; + $str = ''; + + $str .= ''; + $str .= ''; + $str .= ''; + $str .= $this->writeColorScheme(); + $str .= $this->writeFontScheme(); + $str .= $this->writeFormatScheme(); + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + + return $str; + } + + + /** + * Write color scheme + * + * @return string + */ + private function writeColorScheme() + { + $str = ''; + + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + + return $str; + } + + /** + * Write font scheme + * + * @return string + */ + private function writeFontScheme() + { + $str = ''; + + $str .= ''; + + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + + $str .= ''; + + return $str; + } + + /** + * Write format scheme + * + * @return string + */ + private function writeFormatScheme() + { + $str = ''; + + $str .= ''; + $str .= $this->writeFormatFill(); + $str .= $this->writeFormatLine(); + $str .= $this->writeFormatEffect(); + $str .= $this->writeFormatBackground(); + $str .= ''; + + return $str; + } + + /** + * Write fill format scheme + * + * @return string + */ + private function writeFormatFill() + { + $str = ''; + + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + + return $str; + } + + /** + * Write line format scheme + * + * @return string + */ + private function writeFormatLine() + { + $str = ''; + + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + + return $str; + } + + /** + * Write effect format scheme + * + * @return string + */ + private function writeFormatEffect() + { + $str = ''; + + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + + return $str; + } + + /** + * Write background format scheme + * + * @return string + */ + private function writeFormatBackground() + { + $str = ''; + + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + $str .= ''; + + return $str; } } diff --git a/src/PhpWord/Writer/Word2007/Style/AbstractStyle.php b/src/PhpWord/Writer/Word2007/Style/AbstractStyle.php index 06c35117..61c8bae8 100644 --- a/src/PhpWord/Writer/Word2007/Style/AbstractStyle.php +++ b/src/PhpWord/Writer/Word2007/Style/AbstractStyle.php @@ -49,6 +49,7 @@ abstract class AbstractStyle /** * Create new instance * + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param string|\PhpOffice\PhpWord\Style\AbstractStyle $style */ public function __construct(XMLWriter $xmlWriter, $style = null) @@ -81,16 +82,24 @@ abstract class AbstractStyle * Convert twip value * * @param int|float $value - * @param int|float $default + * @param int $default (int|float) * @return int|float */ protected function convertTwip($value, $default = 0) { + $factors = array( + Settings::UNIT_CM => 567, + Settings::UNIT_MM => 56.7, + Settings::UNIT_INCH => 1440, + Settings::UNIT_POINT => 20, + Settings::UNIT_PICA => 240, + ); $unit = Settings::getMeasurementUnit(); - if ($unit == Settings::UNIT_TWIP || $value == $default) { - return $value; - } else { - return $value * $unit; + $factor = 1; + if (in_array($unit, $factors) && $value != $default) { + $factor = $factors[$unit]; } + + return $value * $factor; } } diff --git a/src/PhpWord/Writer/Word2007/Style/Alignment.php b/src/PhpWord/Writer/Word2007/Style/Alignment.php new file mode 100644 index 00000000..cefadb57 --- /dev/null +++ b/src/PhpWord/Writer/Word2007/Style/Alignment.php @@ -0,0 +1,44 @@ +getStyle(); + if (!$style instanceof \PhpOffice\PhpWord\Style\Alignment) { + return; + } + $value = $style->getValue(); + if ($value !== null) { + $xmlWriter = $this->getXmlWriter(); + $xmlWriter->startElement('w:jc'); + $xmlWriter->writeAttribute('w:val', $value); + $xmlWriter->endElement(); // w:jc + } + } +} diff --git a/src/PhpWord/Writer/Word2007/Style/Cell.php b/src/PhpWord/Writer/Word2007/Style/Cell.php index c6e21625..a4b1ae90 100644 --- a/src/PhpWord/Writer/Word2007/Style/Cell.php +++ b/src/PhpWord/Writer/Word2007/Style/Cell.php @@ -26,17 +26,30 @@ use PhpOffice\PhpWord\Style\Cell as CellStyle; */ class Cell extends AbstractStyle { + /** + * @var int Cell width + */ + private $width; + /** * Write style */ public function write() { $style = $this->getStyle(); - if (!$style instanceof \PhpOffice\PhpWord\Style\Cell) { + if (!$style instanceof CellStyle) { return; } $xmlWriter = $this->getXmlWriter(); + $xmlWriter->startElement('w:tcPr'); + + // Width + $xmlWriter->startElement('w:tcW'); + $xmlWriter->writeAttribute('w:w', $this->width); + $xmlWriter->writeAttribute('w:type', 'dxa'); + $xmlWriter->endElement(); // w:tcW + // Text direction $textDir = $style->getTextDirection(); $xmlWriter->writeElementIf(!is_null($textDir), 'w:textDirection', 'w:val', $textDir); @@ -46,7 +59,7 @@ class Cell extends AbstractStyle $xmlWriter->writeElementIf(!is_null($vAlign), 'w:vAlign', 'w:val', $vAlign); // Border - if ($style->hasBorders()) { + if ($style->hasBorder()) { $xmlWriter->startElement('w:tcBorders'); $styleWriter = new MarginBorder($xmlWriter); @@ -70,5 +83,17 @@ class Cell extends AbstractStyle $vMerge = $style->getVMerge(); $xmlWriter->writeElementIf(!is_null($gridSpan), 'w:gridSpan', 'w:val', $gridSpan); $xmlWriter->writeElementIf(!is_null($vMerge), 'w:vMerge', 'w:val', $vMerge); + + $xmlWriter->endElement(); // w:tcPr + } + + /** + * Set width + * + * @param int $value + */ + public function setWidth($value = null) + { + $this->width = $value; } } diff --git a/src/PhpWord/Writer/Word2007/Style/Font.php b/src/PhpWord/Writer/Word2007/Style/Font.php index 851bca22..0ef22f08 100644 --- a/src/PhpWord/Writer/Word2007/Style/Font.php +++ b/src/PhpWord/Writer/Word2007/Style/Font.php @@ -17,8 +17,6 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Style; -use PhpOffice\PhpWord\PhpWord; - /** * Font style writer * @@ -72,24 +70,24 @@ class Font extends AbstractStyle // Font name/family $font = $style->getName(); $hint = $style->getHint(); - if ($font != PhpWord::DEFAULT_FONT_NAME) { + if ($font !== null) { $xmlWriter->startElement('w:rFonts'); $xmlWriter->writeAttribute('w:ascii', $font); $xmlWriter->writeAttribute('w:hAnsi', $font); $xmlWriter->writeAttribute('w:eastAsia', $font); $xmlWriter->writeAttribute('w:cs', $font); - $xmlWriter->writeAttributeIf($hint != PhpWord::DEFAULT_FONT_CONTENT_TYPE, 'w:hint', $hint); + $xmlWriter->writeAttributeIf($hint !== null, 'w:hint', $hint); $xmlWriter->endElement(); } // Color $color = $style->getColor(); - $xmlWriter->writeElementIf($color != PhpWord::DEFAULT_FONT_COLOR, 'w:color', 'w:val', $color); + $xmlWriter->writeElementIf($color !== null, 'w:color', 'w:val', $color); // Size $size = $style->getSize(); - $xmlWriter->writeElementIf($size != PhpWord::DEFAULT_FONT_SIZE, 'w:sz', 'w:val', $size * 2); - $xmlWriter->writeElementIf($size != PhpWord::DEFAULT_FONT_SIZE, 'w:szCs', 'w:val', $size * 2); + $xmlWriter->writeElementIf($size !== null, 'w:sz', 'w:val', $size * 2); + $xmlWriter->writeElementIf($size !== null, 'w:szCs', 'w:val', $size * 2); // Bold, italic $xmlWriter->writeElementIf($style->isBold(), 'w:b'); diff --git a/src/PhpWord/Writer/Word2007/Style/Image.php b/src/PhpWord/Writer/Word2007/Style/Image.php index a891625b..36b308f1 100644 --- a/src/PhpWord/Writer/Word2007/Style/Image.php +++ b/src/PhpWord/Writer/Word2007/Style/Image.php @@ -17,6 +17,7 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Style; +use PhpOffice\PhpWord\Style\Alignment as AlignmentStyle; use PhpOffice\PhpWord\Style\Image as ImageStyle; /** @@ -39,36 +40,18 @@ class Image extends AbstractStyle public function write() { $style = $this->getStyle(); - if (!$style instanceof \PhpOffice\PhpWord\Style\Image) { + if (!$style instanceof ImageStyle) { return; } - $this->writeStyle(); - } - - /** - * Write w10 wrapping - * - * @return array - */ - public function writeW10Wrap() - { - if (is_null($this->w10wrap)) { - return; - } - - $xmlWriter = $this->getXmlWriter(); - $xmlWriter->startElement('w10:wrap'); - $xmlWriter->writeAttribute('type', $this->w10wrap); - $xmlWriter->endElement(); // w10:wrap + $this->writeStyle($style); } /** * Write style attribute */ - protected function writeStyle() + protected function writeStyle(ImageStyle $style) { $xmlWriter = $this->getXmlWriter(); - $style = $this->getStyle(); // Default style array $styleArray = array( @@ -77,7 +60,7 @@ class Image extends AbstractStyle 'mso-width-relative' => 'margin', 'mso-height-relative' => 'margin', ); - $styleArray = array_merge($styleArray, $this->getElementStyle()); + $styleArray = array_merge($styleArray, $this->getElementStyle($style)); // Absolute/relative positioning $positioning = $style->getPositioning(); @@ -119,13 +102,45 @@ class Image extends AbstractStyle } /** - * Get element style - * - * @return array + * Write alignment */ - private function getElementStyle() + public function writeAlignment() { $style = $this->getStyle(); + if (!$style instanceof ImageStyle) { + return; + } + + $xmlWriter = $this->getXmlWriter(); + $xmlWriter->startElement('w:pPr'); + $styleWriter = new Alignment($xmlWriter, new AlignmentStyle(array('value' => $style->getAlign()))); + $styleWriter->write(); + $xmlWriter->endElement(); // w:pPr + } + + /** + * Write w10 wrapping + */ + public function writeW10Wrap() + { + if (is_null($this->w10wrap)) { + return; + } + + $xmlWriter = $this->getXmlWriter(); + $xmlWriter->startElement('w10:wrap'); + $xmlWriter->writeAttribute('type', $this->w10wrap); + $xmlWriter->endElement(); // w10:wrap + } + + /** + * Get element style + * + * @param \PhpOffice\PhpWord\Style\Image $style + * @return array + */ + private function getElementStyle(ImageStyle $style) + { $styles = array(); $styleValues = array( 'width' => $style->getWidth(), diff --git a/src/PhpWord/Writer/Word2007/Style/MarginBorder.php b/src/PhpWord/Writer/Word2007/Style/MarginBorder.php index 28cf1224..23143ef5 100644 --- a/src/PhpWord/Writer/Word2007/Style/MarginBorder.php +++ b/src/PhpWord/Writer/Word2007/Style/MarginBorder.php @@ -17,6 +17,8 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Style; +use PhpOffice\PhpWord\Shared\XMLWriter; + /** * Margin border style writer * @@ -56,31 +58,48 @@ class MarginBorder extends AbstractStyle $sizeCount = count($this->sizes) - 1; for ($i = 0; $i < $sizeCount; $i++) { - if (!is_null($this->sizes[$i])) { - $xmlWriter->startElement('w:' . $sides[$i]); - if (!empty($this->colors)) { - if (is_null($this->colors[$i]) && !empty($this->attributes)) { - if (array_key_exists('defaultColor', $this->attributes)) { - $this->colors[$i] = $this->attributes['defaultColor']; - } - } - $xmlWriter->writeAttribute('w:val', 'single'); - $xmlWriter->writeAttribute('w:sz', $this->sizes[$i]); - $xmlWriter->writeAttribute('w:color', $this->colors[$i]); - if (!empty($this->attributes)) { - if (array_key_exists('space', $this->attributes)) { - $xmlWriter->writeAttribute('w:space', $this->attributes['space']); - } - } - } else { - $xmlWriter->writeAttribute('w:w', $this->sizes[$i]); - $xmlWriter->writeAttribute('w:type', 'dxa'); + if ($this->sizes[$i] !== null) { + $color = null; + if (isset($this->colors[$i])) { + $color = $this->colors[$i]; } - $xmlWriter->endElement(); + $this->writeSide($xmlWriter, $sides[$i], $this->sizes[$i], $color); } } } + /** + * Write side + * + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @param string $side + * @param int $width + * @param string $color + */ + private function writeSide(XMLWriter $xmlWriter, $side, $width, $color = null) + { + $xmlWriter->startElement('w:' . $side); + if (!empty($this->colors)) { + if ($color === null && !empty($this->attributes)) { + if (array_key_exists('defaultColor', $this->attributes)) { + $color = $this->attributes['defaultColor']; + } + } + $xmlWriter->writeAttribute('w:val', 'single'); + $xmlWriter->writeAttribute('w:sz', $width); + $xmlWriter->writeAttribute('w:color', $color); + if (!empty($this->attributes)) { + if (array_key_exists('space', $this->attributes)) { + $xmlWriter->writeAttribute('w:space', $this->attributes['space']); + } + } + } else { + $xmlWriter->writeAttribute('w:w', $width); + $xmlWriter->writeAttribute('w:type', 'dxa'); + } + $xmlWriter->endElement(); + } + /** * Set sizes * diff --git a/src/PhpWord/Writer/Word2007/Style/Paragraph.php b/src/PhpWord/Writer/Word2007/Style/Paragraph.php index 88a75845..7322fd91 100644 --- a/src/PhpWord/Writer/Word2007/Style/Paragraph.php +++ b/src/PhpWord/Writer/Word2007/Style/Paragraph.php @@ -17,6 +17,8 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Style; +use PhpOffice\PhpWord\Style\Alignment as AlignmentStyle; + /** * Paragraph style writer * @@ -81,8 +83,8 @@ class Paragraph extends AbstractStyle $xmlWriter->writeElementIf(!is_null($styleName), 'w:pStyle', 'w:val', $styleName); // Alignment - $align = $style->getAlign(); - $xmlWriter->writeElementIf(!is_null($align), 'w:jc', 'w:val', $align); + $styleWriter = new Alignment($xmlWriter, new AlignmentStyle(array('value' => $style->getAlign()))); + $styleWriter->write(); // Pagination $xmlWriter->writeElementIf(!$style->hasWidowControl(), 'w:widowControl', 'w:val', '0'); diff --git a/src/PhpWord/Writer/Word2007/Style/Row.php b/src/PhpWord/Writer/Word2007/Style/Row.php new file mode 100644 index 00000000..5517cc2b --- /dev/null +++ b/src/PhpWord/Writer/Word2007/Style/Row.php @@ -0,0 +1,66 @@ +getStyle(); + if (!$style instanceof \PhpOffice\PhpWord\Style\Row) { + return; + } + + $xmlWriter = $this->getXmlWriter(); + $xmlWriter->startElement('w:trPr'); + + if ($this->height !== null) { + $xmlWriter->startElement('w:trHeight'); + $xmlWriter->writeAttribute('w:val', $this->height); + $xmlWriter->writeAttribute('w:hRule', ($style->isExactHeight() ? 'exact' : 'atLeast')); + $xmlWriter->endElement(); + } + $xmlWriter->writeElementIf($style->isTblHeader(), 'w:tblHeader', 'w:val', '1'); + $xmlWriter->writeElementIf($style->isCantSplit(), 'w:cantSplit', 'w:val', '1'); + + $xmlWriter->endElement(); // w:trPr + } + + /** + * Set height + * + * @param int $value + */ + public function setHeight($value = null) + { + $this->height = $value; + } +} diff --git a/src/PhpWord/Writer/Word2007/Style/Section.php b/src/PhpWord/Writer/Word2007/Style/Section.php index 61658e03..fb32a39a 100644 --- a/src/PhpWord/Writer/Word2007/Style/Section.php +++ b/src/PhpWord/Writer/Word2007/Style/Section.php @@ -32,7 +32,7 @@ class Section extends AbstractStyle public function write() { $style = $this->getStyle(); - if (!$style instanceof \PhpOffice\PhpWord\Style\Section) { + if (!$style instanceof SectionStyle) { return; } $xmlWriter = $this->getXmlWriter(); @@ -66,7 +66,7 @@ class Section extends AbstractStyle $xmlWriter->endElement(); // Borders - if ($style->hasBorders()) { + if ($style->hasBorder()) { $xmlWriter->startElement('w:pgBorders'); $xmlWriter->writeAttribute('w:offsetFrom', 'page'); diff --git a/src/PhpWord/Writer/Word2007/Style/Table.php b/src/PhpWord/Writer/Word2007/Style/Table.php index 0a0241c3..e89b121c 100644 --- a/src/PhpWord/Writer/Word2007/Style/Table.php +++ b/src/PhpWord/Writer/Word2007/Style/Table.php @@ -17,6 +17,10 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Style; +use PhpOffice\PhpWord\Shared\XMLWriter; +use PhpOffice\PhpWord\Style\Alignment as AlignmentStyle; +use PhpOffice\PhpWord\Style\Table as TableStyle; + /** * Table style writer * @@ -25,11 +29,9 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Style; class Table extends AbstractStyle { /** - * Is full style - * - * @var bool + * @var int Table width */ - private $isFullStyle = true; + private $width; /** * Write style @@ -37,89 +39,135 @@ class Table extends AbstractStyle public function write() { $style = $this->getStyle(); - if (!$style instanceof \PhpOffice\PhpWord\Style\Table) { - return; - } $xmlWriter = $this->getXmlWriter(); - $hasBorders = $style->hasBorders(); - $hasMargins = $style->hasMargins(); - if ($hasMargins || $hasBorders) { + if ($style instanceof TableStyle) { + $this->writeStyle($xmlWriter, $style); + } elseif (is_string($style)) { $xmlWriter->startElement('w:tblPr'); - if ($hasMargins) { - $mbWriter = new MarginBorder($xmlWriter); - $mbWriter->setSizes($style->getCellMargin()); - - $xmlWriter->startElement('w:tblCellMar'); - $mbWriter->write(); - $xmlWriter->endElement(); // w:tblCellMar - } - if ($hasBorders) { - $mbWriter = new MarginBorder($xmlWriter); - $mbWriter->setSizes($style->getBorderSize()); - $mbWriter->setColors($style->getBorderColor()); - - $xmlWriter->startElement('w:tblBorders'); - $mbWriter->write(); - $xmlWriter->endElement(); // w:tblBorders - } - $xmlWriter->endElement(); // w:tblPr - } - - // Only write background color and first row for full style - if ($this->isFullStyle) { - // Background color - if (!is_null($style->getShading())) { - $xmlWriter->startElement('w:tcPr'); - $styleWriter = new Shading($xmlWriter, $style->getShading()); - $styleWriter->write(); - $xmlWriter->endElement(); - } - // First Row - $firstRow = $style->getFirstRow(); - if ($firstRow instanceof \PhpOffice\PhpWord\Style\Table) { - $this->writeFirstRow($firstRow); + $xmlWriter->startElement('w:tblStyle'); + $xmlWriter->writeAttribute('w:val', $style); + $xmlWriter->endElement(); + if ($this->width !== null) { + $this->writeWidth($xmlWriter, $this->width, 'pct'); } + $xmlWriter->endElement(); } } /** - * Set is full style - * - * @param bool $value + * Write full style */ - public function setIsFullStyle($value) + private function writeStyle(XMLWriter $xmlWriter, TableStyle $style) { - $this->isFullStyle = $value; + // w:tblPr + $xmlWriter->startElement('w:tblPr'); + + // Alignment + $styleWriter = new Alignment($xmlWriter, new AlignmentStyle(array('value' => $style->getAlign()))); + $styleWriter->write(); + + $this->writeWidth($xmlWriter, $style->getWidth(), $style->getUnit()); + $this->writeMargin($xmlWriter, $style); + $this->writeBorder($xmlWriter, $style); + + $xmlWriter->endElement(); // w:tblPr + + $this->writeShading($xmlWriter, $style); + + // First row style + $firstRow = $style->getFirstRow(); + if ($firstRow instanceof TableStyle) { + $this->writeFirstRow($xmlWriter, $firstRow); + } + } + + /** + * Write width + * + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @param int $width + * @param string $unit + */ + private function writeWidth(XMLWriter $xmlWriter, $width, $unit) + { + $xmlWriter->startElement('w:tblW'); + $xmlWriter->writeAttribute('w:w', $width); + $xmlWriter->writeAttribute('w:type', $unit); + $xmlWriter->endElement(); // w:tblW + } + + /** + * Write margin + */ + private function writeMargin(XMLWriter $xmlWriter, TableStyle $style) + { + if ($style->hasMargin()) { + $xmlWriter->startElement('w:tblCellMar'); + + $styleWriter = new MarginBorder($xmlWriter); + $styleWriter->setSizes($style->getCellMargin()); + $styleWriter->write(); + + $xmlWriter->endElement(); // w:tblCellMar + } + } + + /** + * Write border + */ + private function writeBorder(XMLWriter $xmlWriter, TableStyle $style) + { + if ($style->hasBorder()) { + $xmlWriter->startElement('w:tblBorders'); + + $styleWriter = new MarginBorder($xmlWriter); + $styleWriter->setSizes($style->getBorderSize()); + $styleWriter->setColors($style->getBorderColor()); + $styleWriter->write(); + + $xmlWriter->endElement(); // w:tblBorders + } } /** * Write row style */ - private function writeFirstRow(\PhpOffice\PhpWord\Style\Table $style) + private function writeFirstRow(XMLWriter $xmlWriter, TableStyle $style) { - $xmlWriter = $this->getXmlWriter(); - $xmlWriter->startElement('w:tblStylePr'); $xmlWriter->writeAttribute('w:type', 'firstRow'); $xmlWriter->startElement('w:tcPr'); - if (!is_null($style->getShading())) { - $styleWriter = new Shading($xmlWriter, $style->getShading()); - $styleWriter->write(); - } - // Borders - if ($style->hasBorders()) { - $mbWriter = new MarginBorder($xmlWriter); - $mbWriter->setSizes($style->getBorderSize()); - $mbWriter->setColors($style->getBorderColor()); - - $xmlWriter->startElement('w:tcBorders'); - $mbWriter->write(); - $xmlWriter->endElement(); // w:tcBorders - } + $this->writeBorder($xmlWriter, $style); + $this->writeShading($xmlWriter, $style); $xmlWriter->endElement(); // w:tcPr $xmlWriter->endElement(); // w:tblStylePr } + + /** + * Write shading + */ + private function writeShading(XMLWriter $xmlWriter, TableStyle $style) + { + if ($style->getShading() !== null) { + $xmlWriter->startElement('w:tcPr'); + + $styleWriter = new Shading($xmlWriter, $style->getShading()); + $styleWriter->write(); + + $xmlWriter->endElement(); + } + } + + /** + * Set width + * + * @param int $value + */ + public function setWidth($value = null) + { + $this->width = $value; + } } diff --git a/src/PhpWord/Writer/Word2007/Style/TextBox.php b/src/PhpWord/Writer/Word2007/Style/TextBox.php index 2bbe40e9..13f40256 100644 --- a/src/PhpWord/Writer/Word2007/Style/TextBox.php +++ b/src/PhpWord/Writer/Word2007/Style/TextBox.php @@ -32,11 +32,11 @@ class TextBox extends Image public function write() { $style = $this->getStyle(); - if (!$style instanceof \PhpOffice\PhpWord\Style\TextBox) { + if (!$style instanceof TextBoxStyle) { return; } - $this->writeStyle(); - $this->writeBorder(); + $this->writeStyle($style); + $this->writeBorder($style); } /** @@ -50,6 +50,9 @@ class TextBox extends Image return; } $style = $this->getStyle(); + if (!$style instanceof TextBoxStyle) { + return; + } $relativePositions = array( TextBoxStyle::POSITION_RELATIVE_TO_MARGIN => 'margin', @@ -88,7 +91,7 @@ class TextBox extends Image public function writeInnerMargin() { $style = $this->getStyle(); - if (!$style->hasInnerMargins()) { + if (!$style instanceof TextBoxStyle || !$style->hasInnerMargins()) { return; } @@ -100,10 +103,9 @@ class TextBox extends Image /** * Writer border */ - private function writeBorder() + private function writeBorder(TextBoxStyle $style) { $xmlWriter = $this->getXmlWriter(); - $style = $this->getStyle(); // Border size $borderSize = $style->getBorderSize(); diff --git a/src/PhpWord/Writer/WriterInterface.php b/src/PhpWord/Writer/WriterInterface.php index a56bcf8f..eda99f27 100644 --- a/src/PhpWord/Writer/WriterInterface.php +++ b/src/PhpWord/Writer/WriterInterface.php @@ -25,7 +25,7 @@ interface WriterInterface /** * Save PhpWord to file * - * @param string $pFilename + * @param string $filename */ - public function save($pFilename = null); + public function save($filename = null); } diff --git a/tests/PhpWord/Tests/Element/CellTest.php b/tests/PhpWord/Tests/Element/CellTest.php index 466188f6..aa07ec03 100644 --- a/tests/PhpWord/Tests/Element/CellTest.php +++ b/tests/PhpWord/Tests/Element/CellTest.php @@ -31,8 +31,7 @@ class CellTest extends \PHPUnit_Framework_TestCase */ public function testConstruct() { - $iVal = rand(1, 1000); - $oCell = new Cell('section', $iVal); + $oCell = new Cell(); $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Cell', $oCell); $this->assertEquals($oCell->getWidth(), null); @@ -43,8 +42,7 @@ class CellTest extends \PHPUnit_Framework_TestCase */ public function testConstructWithStyleArray() { - $iVal = rand(1, 1000); - $oCell = new Cell('section', $iVal, null, array('valign' => 'center')); + $oCell = new Cell(null, array('valign' => 'center')); $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Cell', $oCell->getStyle()); $this->assertEquals($oCell->getWidth(), null); @@ -55,7 +53,7 @@ class CellTest extends \PHPUnit_Framework_TestCase */ public function testAddText() { - $oCell = new Cell('section', 1); + $oCell = new Cell(); $element = $oCell->addText('text'); $this->assertCount(1, $oCell->getElements()); @@ -67,7 +65,7 @@ class CellTest extends \PHPUnit_Framework_TestCase */ public function testAddTextNotUTF8() { - $oCell = new Cell('section', 1); + $oCell = new Cell(); $element = $oCell->addText(utf8_decode('ééé')); $this->assertCount(1, $oCell->getElements()); @@ -80,7 +78,7 @@ class CellTest extends \PHPUnit_Framework_TestCase */ public function testAddLink() { - $oCell = new Cell('section', 1); + $oCell = new Cell(); $element = $oCell->addLink(utf8_decode('ééé'), utf8_decode('ééé')); $this->assertCount(1, $oCell->getElements()); @@ -92,7 +90,7 @@ class CellTest extends \PHPUnit_Framework_TestCase */ public function testAddTextBreak() { - $oCell = new Cell('section', 1); + $oCell = new Cell(); $oCell->addTextBreak(); $this->assertCount(1, $oCell->getElements()); @@ -103,7 +101,7 @@ class CellTest extends \PHPUnit_Framework_TestCase */ public function testAddListItem() { - $oCell = new Cell('section', 1); + $oCell = new Cell(); $element = $oCell->addListItem('text'); $this->assertCount(1, $oCell->getElements()); @@ -116,7 +114,7 @@ class CellTest extends \PHPUnit_Framework_TestCase */ public function testAddListItemNotUTF8() { - $oCell = new Cell('section', 1); + $oCell = new Cell(); $element = $oCell->addListItem(utf8_decode('ééé')); $this->assertCount(1, $oCell->getElements()); @@ -130,7 +128,7 @@ class CellTest extends \PHPUnit_Framework_TestCase public function testAddImageSection() { $src = __DIR__ . "/../_files/images/earth.jpg"; - $oCell = new Cell('section', 1); + $oCell = new Cell(); $element = $oCell->addImage($src); $this->assertCount(1, $oCell->getElements()); @@ -168,37 +166,9 @@ class CellTest extends \PHPUnit_Framework_TestCase */ public function testAddImageSectionByUrl() { - $oCell = new Cell('section', 1); + $oCell = new Cell(); $element = $oCell->addImage( - 'https://assets.mozillalabs.com/Brands-Logos/Thunderbird/logo-only/thunderbird_logo-only_RGB.png' - ); - - $this->assertCount(1, $oCell->getElements()); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Image', $element); - } - - /** - * Add image header by URL - */ - public function testAddImageHeaderByUrl() - { - $oCell = new Cell('header', 1); - $element = $oCell->addImage( - 'https://assets.mozillalabs.com/Brands-Logos/Thunderbird/logo-only/thunderbird_logo-only_RGB.png' - ); - - $this->assertCount(1, $oCell->getElements()); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Image', $element); - } - - /** - * Add image footer by URL - */ - public function testAddImageFooterByUrl() - { - $oCell = new Cell('footer', 1); - $element = $oCell->addImage( - 'https://assets.mozillalabs.com/Brands-Logos/Thunderbird/logo-only/thunderbird_logo-only_RGB.png' + 'http://php.net/images/logos/php-med-trans-light.gif' ); $this->assertCount(1, $oCell->getElements()); @@ -211,7 +181,7 @@ class CellTest extends \PHPUnit_Framework_TestCase public function testAddObjectXLS() { $src = __DIR__ . "/../_files/documents/sheet.xls"; - $oCell = new Cell('section', 1); + $oCell = new Cell(); $element = $oCell->addObject($src); $this->assertCount(1, $oCell->getElements()); @@ -226,7 +196,7 @@ class CellTest extends \PHPUnit_Framework_TestCase public function testAddObjectException() { $src = __DIR__ . "/../_files/xsl/passthrough.xsl"; - $oCell = new Cell('section', 1); + $oCell = new Cell(); $oCell->addObject($src); } @@ -235,7 +205,8 @@ class CellTest extends \PHPUnit_Framework_TestCase */ public function testAddPreserveText() { - $oCell = new Cell('header', 1); + $oCell = new Cell(); + $oCell->setDocPart('Header', 1); $element = $oCell->addPreserveText('text'); $this->assertCount(1, $oCell->getElements()); @@ -247,7 +218,8 @@ class CellTest extends \PHPUnit_Framework_TestCase */ public function testAddPreserveTextNotUTF8() { - $oCell = new Cell('header', 1); + $oCell = new Cell(); + $oCell->setDocPart('Header', 1); $element = $oCell->addPreserveText(utf8_decode('ééé')); $this->assertCount(1, $oCell->getElements()); @@ -262,7 +234,8 @@ class CellTest extends \PHPUnit_Framework_TestCase */ public function testAddPreserveTextException() { - $oCell = new Cell('section', 1); + $oCell = new Cell(); + $oCell->setDocPart('Section', 1); $oCell->addPreserveText('text'); } @@ -271,7 +244,7 @@ class CellTest extends \PHPUnit_Framework_TestCase */ public function testCreateTextRun() { - $oCell = new Cell('section', 1); + $oCell = new Cell(); $element = $oCell->addTextRun(); $this->assertCount(1, $oCell->getElements()); @@ -283,7 +256,7 @@ class CellTest extends \PHPUnit_Framework_TestCase */ public function testAddCheckBox() { - $oCell = new Cell('section', 1); + $oCell = new Cell(); $element = $oCell->addCheckBox(utf8_decode('ééé'), utf8_decode('ééé')); $this->assertCount(1, $oCell->getElements()); @@ -295,7 +268,7 @@ class CellTest extends \PHPUnit_Framework_TestCase */ public function testGetElements() { - $oCell = new Cell('section', 1); + $oCell = new Cell(); $this->assertInternalType('array', $oCell->getElements()); } diff --git a/tests/PhpWord/Tests/Element/FooterTest.php b/tests/PhpWord/Tests/Element/FooterTest.php index d2a76705..c5d04b41 100644 --- a/tests/PhpWord/Tests/Element/FooterTest.php +++ b/tests/PhpWord/Tests/Element/FooterTest.php @@ -119,7 +119,7 @@ class FooterTest extends \PHPUnit_Framework_TestCase { $oFooter = new Footer(1); $element = $oFooter->addImage( - 'https://assets.mozillalabs.com/Brands-Logos/Thunderbird/logo-only/thunderbird_logo-only_RGB.png' + 'http://php.net/images/logos/php-med-trans-light.gif' ); $this->assertCount(1, $oFooter->getElements()); diff --git a/tests/PhpWord/Tests/Element/HeaderTest.php b/tests/PhpWord/Tests/Element/HeaderTest.php index 5b64b111..796b24f0 100644 --- a/tests/PhpWord/Tests/Element/HeaderTest.php +++ b/tests/PhpWord/Tests/Element/HeaderTest.php @@ -128,7 +128,7 @@ class HeaderTest extends \PHPUnit_Framework_TestCase { $oHeader = new Header(1); $element = $oHeader->addImage( - 'https://assets.mozillalabs.com/Brands-Logos/Thunderbird/logo-only/thunderbird_logo-only_RGB.png' + 'http://php.net/images/logos/php-med-trans-light.gif' ); $this->assertCount(1, $oHeader->getElements()); diff --git a/tests/PhpWord/Tests/Element/ListItemRunTest.php b/tests/PhpWord/Tests/Element/ListItemRunTest.php index 5b3f72c8..c034a8f8 100644 --- a/tests/PhpWord/Tests/Element/ListItemRunTest.php +++ b/tests/PhpWord/Tests/Element/ListItemRunTest.php @@ -44,7 +44,7 @@ class ListItemRunTest extends \PHPUnit_Framework_TestCase */ public function testConstructString() { - $oListItemRun = new ListItemRun(0, null, null, 'pStyle'); + $oListItemRun = new ListItemRun(0, null, 'pStyle'); $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\ListItemRun', $oListItemRun); $this->assertCount(0, $oListItemRun->getElements()); @@ -56,29 +56,22 @@ class ListItemRunTest extends \PHPUnit_Framework_TestCase */ public function testConstructArray() { - $oListItemRun = new ListItemRun(0, null, null, array('spacing' => 100)); + $oListItemRun = new ListItemRun(0, null, array('spacing' => 100)); $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\ListItemRun', $oListItemRun); $this->assertCount(0, $oListItemRun->getElements()); $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Paragraph', $oListItemRun->getParagraphStyle()); } - + /** * Get style */ public function testStyle() { - $oListItemRun = new ListItemRun( - 1, - null, - array('listType' => \PhpOffice\PhpWord\Style\ListItem::TYPE_NUMBER) - ); - + $oListItemRun = new ListItemRun(1, array('listType' => \PhpOffice\PhpWord\Style\ListItem::TYPE_NUMBER)); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\ListItem', $oListItemRun->getStyle()); - $this->assertEquals( - $oListItemRun->getStyle()->getListType(), - \PhpOffice\PhpWord\Style\ListItem::TYPE_NUMBER - ); + $this->assertEquals($oListItemRun->getStyle()->getListType(), \PhpOffice\PhpWord\Style\ListItem::TYPE_NUMBER); } /** * getDepth @@ -87,10 +80,10 @@ class ListItemRunTest extends \PHPUnit_Framework_TestCase { $iVal = rand(1, 1000); $oListItemRun = new ListItemRun($iVal); - + $this->assertEquals($oListItemRun->getDepth(), $iVal); } - + /** * Add text */ diff --git a/tests/PhpWord/Tests/Element/RowTest.php b/tests/PhpWord/Tests/Element/RowTest.php index b0de3910..c377bb7c 100644 --- a/tests/PhpWord/Tests/Element/RowTest.php +++ b/tests/PhpWord/Tests/Element/RowTest.php @@ -32,8 +32,7 @@ class RowTest extends \PHPUnit_Framework_TestCase */ public function testConstruct() { - $iVal = rand(1, 1000); - $oRow = new Row('section', $iVal); + $oRow = new Row(); $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Row', $oRow); $this->assertEquals($oRow->getHeight(), null); @@ -48,15 +47,9 @@ class RowTest extends \PHPUnit_Framework_TestCase public function testConstructWithParams() { $iVal = rand(1, 1000); - $iVal2 = rand(1, 1000); - $oRow = new Row( - 'section', - $iVal, - $iVal2, - array('borderBottomSize' => 18, 'borderBottomColor' => '0000FF', 'bgColor' => '66BBFF') - ); + $oRow = new Row($iVal, array('borderBottomSize' => 18, 'borderBottomColor' => '0000FF', 'bgColor' => '66BBFF')); - $this->assertEquals($oRow->getHeight(), $iVal2); + $this->assertEquals($oRow->getHeight(), $iVal); $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Row', $oRow->getStyle()); } @@ -65,7 +58,7 @@ class RowTest extends \PHPUnit_Framework_TestCase */ public function testAddCell() { - $oRow = new Row('section', 1); + $oRow = new Row(); $element = $oRow->addCell(); $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Cell', $element); diff --git a/tests/PhpWord/Tests/Element/TitleTest.php b/tests/PhpWord/Tests/Element/TitleTest.php index 5b54cce6..ca65c8eb 100644 --- a/tests/PhpWord/Tests/Element/TitleTest.php +++ b/tests/PhpWord/Tests/Element/TitleTest.php @@ -47,16 +47,4 @@ class TitleTest extends \PHPUnit_Framework_TestCase $this->assertEquals($oTitle->getStyle(), null); } - - /** - * Get bookmark Id - */ - public function testBookmarkID() - { - $oTitle = new Title('text'); - - $iVal = rand(1, 1000); - $oTitle->setBookmarkId($iVal); - $this->assertEquals($oTitle->getBookmarkId(), $iVal); - } } diff --git a/tests/PhpWord/Tests/PhpWordTest.php b/tests/PhpWord/Tests/PhpWordTest.php index 479d2285..6a9e6b26 100644 --- a/tests/PhpWord/Tests/PhpWordTest.php +++ b/tests/PhpWord/Tests/PhpWordTest.php @@ -19,6 +19,7 @@ namespace PhpOffice\PhpWord\Tests; use PhpOffice\PhpWord\DocumentProperties; use PhpOffice\PhpWord\PhpWord; +use PhpOffice\PhpWord\Settings; use PhpOffice\PhpWord\Style; /** @@ -35,8 +36,8 @@ class PhpWordTest extends \PHPUnit_Framework_TestCase { $phpWord = new PhpWord(); $this->assertEquals(new DocumentProperties(), $phpWord->getDocumentProperties()); - $this->assertEquals(PhpWord::DEFAULT_FONT_NAME, $phpWord->getDefaultFontName()); - $this->assertEquals(PhpWord::DEFAULT_FONT_SIZE, $phpWord->getDefaultFontSize()); + $this->assertEquals(Settings::DEFAULT_FONT_NAME, $phpWord->getDefaultFontName()); + $this->assertEquals(Settings::DEFAULT_FONT_SIZE, $phpWord->getDefaultFontSize()); } /** @@ -69,7 +70,7 @@ class PhpWordTest extends \PHPUnit_Framework_TestCase { $phpWord = new PhpWord(); $fontName = 'Times New Roman'; - $this->assertEquals(PhpWord::DEFAULT_FONT_NAME, $phpWord->getDefaultFontName()); + $this->assertEquals(Settings::DEFAULT_FONT_NAME, $phpWord->getDefaultFontName()); $phpWord->setDefaultFontName($fontName); $this->assertEquals($fontName, $phpWord->getDefaultFontName()); } @@ -81,7 +82,7 @@ class PhpWordTest extends \PHPUnit_Framework_TestCase { $phpWord = new PhpWord(); $fontSize = 16; - $this->assertEquals(PhpWord::DEFAULT_FONT_SIZE, $phpWord->getDefaultFontSize()); + $this->assertEquals(Settings::DEFAULT_FONT_SIZE, $phpWord->getDefaultFontSize()); $phpWord->setDefaultFontSize($fontSize); $this->assertEquals($fontSize, $phpWord->getDefaultFontSize()); } diff --git a/tests/PhpWord/Tests/SettingsTest.php b/tests/PhpWord/Tests/SettingsTest.php index 4292c228..d188595e 100644 --- a/tests/PhpWord/Tests/SettingsTest.php +++ b/tests/PhpWord/Tests/SettingsTest.php @@ -34,7 +34,6 @@ class SettingsTest extends \PHPUnit_Framework_TestCase $this->assertTrue(Settings::hasCompatibility()); $this->assertTrue(Settings::setCompatibility(false)); $this->assertFalse(Settings::hasCompatibility()); - $this->assertFalse(Settings::setCompatibility('Non boolean')); } /** @@ -70,4 +69,40 @@ class SettingsTest extends \PHPUnit_Framework_TestCase $this->assertTrue(Settings::setMeasurementUnit(Settings::UNIT_INCH)); $this->assertFalse(Settings::setMeasurementUnit('foo')); } + + /** + * Test set/get default font name + */ + public function testSetGetDefaultFontName() + { + $this->assertEquals(Settings::DEFAULT_FONT_NAME, Settings::getDefaultFontName()); + $this->assertTrue(Settings::setDefaultFontName('Times New Roman')); + $this->assertFalse(Settings::setDefaultFontName(' ')); + } + + /** + * Test set/get default font size + */ + public function testSetGetDefaultFontSize() + { + $this->assertEquals(Settings::DEFAULT_FONT_SIZE, Settings::getDefaultFontSize()); + $this->assertTrue(Settings::setDefaultFontSize(12)); + $this->assertFalse(Settings::setDefaultFontSize(null)); + } + + /** + * Test load config + */ + public function testLoadConfig() + { + $expected = array( + 'compatibility' => true, + 'zipClass' => 'ZipArchive', + 'pdfRendererName' => 'DomPDF', + 'pdfRendererPath' => '', + 'defaultFontName' => 'Arial', + 'defaultFontSize' => 10, + ); + $this->assertEquals($expected, Settings::loadConfig(__DIR__ . '/../../../phpword.ini.dist')); + } } diff --git a/tests/PhpWord/Tests/Shared/ZipArchiveTest.php b/tests/PhpWord/Tests/Shared/ZipArchiveTest.php index 41537a04..11a0d9a3 100644 --- a/tests/PhpWord/Tests/Shared/ZipArchiveTest.php +++ b/tests/PhpWord/Tests/Shared/ZipArchiveTest.php @@ -17,6 +17,7 @@ namespace PhpOffice\PhpWord\Tests\Shared; +use PhpOffice\PhpWord\Settings; use PhpOffice\PhpWord\Shared\ZipArchive; /** @@ -27,28 +28,60 @@ use PhpOffice\PhpWord\Shared\ZipArchive; */ class ZipArchiveTest extends \PHPUnit_Framework_TestCase { + + /** + * Test close method exception: Working in local, not working in Travis + * + * expectedException \PhpOffice\PhpWord\Exception\Exception + * expectedExceptionMessage Could not close zip file + * covers ::close + */ + public function testCloseException() + { + // $zipFile = __DIR__ . "/../_files/documents/ziptest.zip"; + + // $object = new ZipArchive(); + // $object->open($zipFile, ZipArchive::CREATE); + // $object->addFromString('content/string.txt', 'Test'); + + // // Lock the file + // $resource = fopen($zipFile, "w"); + // flock($resource, LOCK_EX); + + // // Closing the file should throws an exception + // $object->close(); + + // // Unlock the file + // flock($resource, LOCK_UN); + // fclose($resource); + + // @unlink($zipFile); + } + /** * Test all methods * + * @param string $zipClass * @covers :: */ - public function testAllMethods() + public function testZipArchive($zipClass = 'ZipArchive') { // Preparation $existingFile = __DIR__ . "/../_files/documents/sheet.xls"; $zipFile = __DIR__ . "/../_files/documents/ziptest.zip"; - $destination1 = __DIR__ . "/../_files/extract1"; - $destination2 = __DIR__ . "/../_files/extract2"; - $destination3 = __DIR__ . "/../_files/extract3"; + $destination1 = __DIR__ . "/../_files/documents/extract1"; + $destination2 = __DIR__ . "/../_files/documents/extract2"; @mkdir($destination1); @mkdir($destination2); - @mkdir($destination3); + + Settings::setZipClass($zipClass); $object = new ZipArchive(); - $object->open($zipFile); + $object->open($zipFile, ZipArchive::CREATE); $object->addFile($existingFile, 'xls/new.xls'); $object->addFromString('content/string.txt', 'Test'); $object->close(); + $object->open($zipFile); // Run tests $this->assertEquals(0, $object->locateName('xls/new.xls')); @@ -68,10 +101,19 @@ class ZipArchiveTest extends \PHPUnit_Framework_TestCase // Cleanup $this->deleteDir($destination1); $this->deleteDir($destination2); - $this->deleteDir($destination3); @unlink($zipFile); } + /** + * Test PclZip + * + * @covers :: + */ + public function testPCLZip() + { + $this->testZipArchive('PhpOffice\PhpWord\Shared\ZipArchive'); + } + /** * Delete directory * diff --git a/tests/PhpWord/Tests/Style/FontTest.php b/tests/PhpWord/Tests/Style/FontTest.php index 74aa5e2e..ca2105fb 100644 --- a/tests/PhpWord/Tests/Style/FontTest.php +++ b/tests/PhpWord/Tests/Style/FontTest.php @@ -18,6 +18,7 @@ namespace PhpOffice\PhpWord\Tests\Style; use PhpOffice\PhpWord\PhpWord; +use PhpOffice\PhpWord\Settings; use PhpOffice\PhpWord\Style\Font; use PhpOffice\PhpWord\Tests\TestHelperDOCX; @@ -55,21 +56,24 @@ class FontTest extends \PHPUnit_Framework_TestCase $object = new Font(); $attributes = array( - 'name' => PhpWord::DEFAULT_FONT_NAME, - 'size' => PhpWord::DEFAULT_FONT_SIZE, + 'name' => null, + 'size' => null, + 'hint' => null, + 'color' => null, 'bold' => false, 'italic' => false, + 'underline' => Font::UNDERLINE_NONE, 'superScript' => false, 'subScript' => false, - 'underline' => Font::UNDERLINE_NONE, 'strikethrough' => false, - 'color' => PhpWord::DEFAULT_FONT_COLOR, + 'doubleStrikethrough' => false, + 'smallCaps' => false, + 'allCaps' => false, 'fgColor' => null, 'bgColor' => null, - 'hint' => PhpWord::DEFAULT_FONT_CONTENT_TYPE, ); foreach ($attributes as $key => $default) { - $get = "get{$key}"; + $get = is_bool($default) ? "is{$key}" : "get{$key}"; $object->setStyleValue("$key", null); $this->assertEquals($default, $object->$get()); $object->setStyleValue("$key", ''); @@ -87,21 +91,24 @@ class FontTest extends \PHPUnit_Framework_TestCase $attributes = array( 'name' => 'Times New Roman', 'size' => 9, + 'color' => '999999', + 'hint' => 'eastAsia', 'bold' => true, 'italic' => true, + 'underline' => Font::UNDERLINE_HEAVY, 'superScript' => true, 'subScript' => false, - 'underline' => Font::UNDERLINE_HEAVY, 'strikethrough' => true, - 'color' => '999999', + 'doubleStrikethrough' => false, + 'smallCaps' => true, + 'allCaps' => false, 'fgColor' => Font::FGCOLOR_YELLOW, 'bgColor' => 'FFFF00', - 'hint' => 'eastAsia', 'lineHeight' => 2, ); $object->setStyleByArray($attributes); foreach ($attributes as $key => $value) { - $get = "get{$key}"; + $get = is_bool($value) ? "is{$key}" : "get{$key}"; $this->assertEquals($value, $object->$get()); } } diff --git a/tests/PhpWord/Tests/Writer/HTML/ElementTest.php b/tests/PhpWord/Tests/Writer/HTML/ElementTest.php new file mode 100644 index 00000000..e12193e8 --- /dev/null +++ b/tests/PhpWord/Tests/Writer/HTML/ElementTest.php @@ -0,0 +1,41 @@ +assertEquals('', $object->write()); + } + } +} diff --git a/tests/PhpWord/Tests/Writer/HTMLTest.php b/tests/PhpWord/Tests/Writer/HTMLTest.php index 1c2a5049..34e9d2bd 100644 --- a/tests/PhpWord/Tests/Writer/HTMLTest.php +++ b/tests/PhpWord/Tests/Writer/HTMLTest.php @@ -64,6 +64,7 @@ class HTMLTest extends \PHPUnit_Framework_TestCase $docProps = $phpWord->getDocumentProperties(); $docProps->setTitle('HTML Test'); + $phpWord->addTitleStyle(1, array('bold' => true)); $phpWord->addFontStyle('Font', array('name' => 'Verdana', 'size' => 11, 'color' => 'FF0000', 'fgColor' => 'FF0000')); $phpWord->addParagraphStyle('Paragraph', array('align' => 'center')); diff --git a/tests/PhpWord/Tests/Writer/ODText/ElementTest.php b/tests/PhpWord/Tests/Writer/ODText/ElementTest.php new file mode 100644 index 00000000..fa9532d1 --- /dev/null +++ b/tests/PhpWord/Tests/Writer/ODText/ElementTest.php @@ -0,0 +1,42 @@ +write(); + + $this->assertEquals('', $xmlWriter->getData()); + } + } +} diff --git a/tests/PhpWord/Tests/Writer/ODText/Part/ContentTest.php b/tests/PhpWord/Tests/Writer/ODText/Part/ContentTest.php index 619e3573..03f0cfeb 100644 --- a/tests/PhpWord/Tests/Writer/ODText/Part/ContentTest.php +++ b/tests/PhpWord/Tests/Writer/ODText/Part/ContentTest.php @@ -84,7 +84,7 @@ class ContentTest extends \PHPUnit_Framework_TestCase $doc = TestHelperDOCX::getDocument($phpWord, 'ODText'); - $element = "/office:document-content/office:body/office:text/text:p"; + $element = "/office:document-content/office:body/office:text/text:section/text:p"; $this->assertEquals($expected, $doc->getElement($element, 'content.xml')->nodeValue); } diff --git a/tests/PhpWord/Tests/Writer/ODTextTest.php b/tests/PhpWord/Tests/Writer/ODTextTest.php index 419e96a0..88e673fb 100644 --- a/tests/PhpWord/Tests/Writer/ODTextTest.php +++ b/tests/PhpWord/Tests/Writer/ODTextTest.php @@ -109,18 +109,6 @@ class ODTextTest extends \PHPUnit_Framework_TestCase $writer->save('php://output'); } - /** - * Save with no PhpWord object assigned - * - * @expectedException \PhpOffice\PhpWord\Exception\Exception - * @expectedExceptionMessage PhpWord object unassigned. - */ - public function testSaveException() - { - $writer = new ODText(); - $writer->save(); - } - /** * Get writer part return null value */ diff --git a/tests/PhpWord/Tests/Writer/PDF/DomPDFTest.php b/tests/PhpWord/Tests/Writer/PDF/DomPDFTest.php index a2c8fb31..a22cb530 100644 --- a/tests/PhpWord/Tests/Writer/PDF/DomPDFTest.php +++ b/tests/PhpWord/Tests/Writer/PDF/DomPDFTest.php @@ -33,7 +33,7 @@ class DomPDFTest extends \PHPUnit_Framework_TestCase public function testConstruct() { define('DOMPDF_ENABLE_AUTOLOAD', false); - $file = __DIR__ . "/../../_files/temp.pdf"; + $file = __DIR__ . "/../../_files/dompdf.pdf"; $phpWord = new PhpWord(); $section = $phpWord->addSection(); diff --git a/tests/PhpWord/Tests/Writer/PDF/MPDFTest.php b/tests/PhpWord/Tests/Writer/PDF/MPDFTest.php new file mode 100644 index 00000000..4728b7f1 --- /dev/null +++ b/tests/PhpWord/Tests/Writer/PDF/MPDFTest.php @@ -0,0 +1,51 @@ +addSection(); + $section->addText('Test 1'); + + $rendererName = Settings::PDF_RENDERER_MPDF; + $rendererLibraryPath = realpath(PHPWORD_TESTS_BASE_DIR . '/../vendor/mpdf/mpdf'); + Settings::setPdfRenderer($rendererName, $rendererLibraryPath); + $writer = new PDF($phpWord); + $writer->save($file); + + $this->assertTrue(file_exists($file)); + + unlink($file); + } +} diff --git a/tests/PhpWord/Tests/Writer/PDF/TCPDFTest.php b/tests/PhpWord/Tests/Writer/PDF/TCPDFTest.php new file mode 100644 index 00000000..c73f0043 --- /dev/null +++ b/tests/PhpWord/Tests/Writer/PDF/TCPDFTest.php @@ -0,0 +1,51 @@ +addSection(); + $section->addText('Test 1'); + + $rendererName = Settings::PDF_RENDERER_TCPDF; + $rendererLibraryPath = realpath(PHPWORD_TESTS_BASE_DIR . '/../vendor/tecnick.com/tcpdf'); + Settings::setPdfRenderer($rendererName, $rendererLibraryPath); + $writer = new PDF($phpWord); + $writer->save($file); + + $this->assertTrue(file_exists($file)); + + unlink($file); + } +} diff --git a/tests/PhpWord/Tests/Writer/RTF/ElementTest.php b/tests/PhpWord/Tests/Writer/RTF/ElementTest.php new file mode 100644 index 00000000..a31117e6 --- /dev/null +++ b/tests/PhpWord/Tests/Writer/RTF/ElementTest.php @@ -0,0 +1,41 @@ +assertEquals('', $object->write()); + } + } +} diff --git a/tests/PhpWord/Tests/Writer/RTFTest.php b/tests/PhpWord/Tests/Writer/RTFTest.php index ad5a13e1..51a66a7d 100644 --- a/tests/PhpWord/Tests/Writer/RTFTest.php +++ b/tests/PhpWord/Tests/Writer/RTFTest.php @@ -59,7 +59,7 @@ class RTFTest extends \PHPUnit_Framework_TestCase $phpWord = new PhpWord(); $phpWord->addFontStyle('Font', array('name' => 'Verdana', 'size' => 11, - 'color' => 'FF0000', 'fgColor' => 'FF0000')); + 'color' => 'FF0000', 'fgColor' => '00FF00')); $phpWord->addParagraphStyle('Paragraph', array('align' => 'center')); $section = $phpWord->addSection(); $section->addText('Test 1', 'Font', 'Paragraph'); @@ -98,16 +98,4 @@ class RTFTest extends \PHPUnit_Framework_TestCase $writer = new RTF($phpWord); $writer->save('php://output'); } - - /** - * Save with no PhpWord object assigned - * - * @expectedException \PhpOffice\PhpWord\Exception\Exception - * @expectedExceptionMessage PhpWord object unassigned. - */ - public function testSaveException() - { - $writer = new RTF(); - $writer->save(); - } } diff --git a/tests/PhpWord/Tests/Writer/Word2007/ElementTest.php b/tests/PhpWord/Tests/Writer/Word2007/ElementTest.php new file mode 100644 index 00000000..4d1d7ce2 --- /dev/null +++ b/tests/PhpWord/Tests/Writer/Word2007/ElementTest.php @@ -0,0 +1,45 @@ +write(); + + $this->assertEquals('', $xmlWriter->getData()); + } + } +} diff --git a/tests/PhpWord/Tests/Writer/Word2007/Part/DocumentTest.php b/tests/PhpWord/Tests/Writer/Word2007/Part/DocumentTest.php index b036c21b..8ed1246f 100644 --- a/tests/PhpWord/Tests/Writer/Word2007/Part/DocumentTest.php +++ b/tests/PhpWord/Tests/Writer/Word2007/Part/DocumentTest.php @@ -68,10 +68,12 @@ class DocumentTest extends \PHPUnit_Framework_TestCase $section = $phpWord->addSection(); $section->addTOC(); $section->addPageBreak(); + $section->addText('After page break.'); $section->addTitle('Title 1', 1); $section->addListItem('List Item 1', 0); $section->addListItem('List Item 2', 0); $section->addListItem('List Item 3', 0); + $section = $phpWord->addSection(); $section->addTitle('Title 2', 2); $section->addObject($objectSrc); @@ -80,6 +82,7 @@ class DocumentTest extends \PHPUnit_Framework_TestCase 'posHorizontalRel' => 'margin', 'posVerticalRel' => 'margin', 'innerMargin' => 10, 'borderSize' => 1, 'borderColor' => '#FF0')); $section->addTextBox(array('wrappingStyle' => 'tight', 'positioning' => 'absolute', 'align' => 'center')); + $section->addListItemRun()->addText('List item run 1'); $doc = TestHelperDOCX::getDocument($phpWord); @@ -113,22 +116,27 @@ class DocumentTest extends \PHPUnit_Framework_TestCase { $objectSrc = __DIR__ . "/../../../_files/documents/sheet.xls"; + $tabs = array(new \PhpOffice\PhpWord\Style\Tab('right', 9090)); $phpWord = new PhpWord(); - $phpWord->addParagraphStyle('pStyle', array('align' => 'center')); // Style #1 + $phpWord->addParagraphStyle('pStyle', array('align' => 'center', 'tabs' => $tabs)); // Style #1 $phpWord->addFontStyle('fStyle', array('size' => '20', 'bold' => true, 'allCaps' => true)); // Style #2 $phpWord->addTitleStyle(1, array('color' => '333333', 'doubleStrikethrough' => true)); // Style #3 + $phpWord->addTableStyle('tStyle', array('borderSize' => 1)); $fontStyle = new Font('text', array('align' => 'center')); + $section = $phpWord->addSection(); - $section->addListItem('List Item', 0, null, null, 'pStyle'); // Style #4 + $section->addListItem('List Item', 0, null, null, 'pStyle'); // Style #5 $section->addObject($objectSrc, array('align' => 'center')); $section->addTOC($fontStyle); $section->addTitle('Title 1', 1); $section->addTOC('fStyle'); + $table = $section->addTable('tStyle'); + $table->setWidth(100); $doc = TestHelperDOCX::getDocument($phpWord); // List item $element = $doc->getElement('/w:document/w:body/w:p[1]/w:pPr/w:numPr/w:numId'); - $this->assertEquals(4, $element->getAttribute('w:val')); + $this->assertEquals(5, $element->getAttribute('w:val')); // Object $element = $doc->getElement('/w:document/w:body/w:p[2]/w:r/w:object/o:OLEObject'); @@ -179,7 +187,7 @@ class DocumentTest extends \PHPUnit_Framework_TestCase $textrun->addTextBreak(); $textrun = $section->addTextRun($aStyle); $textrun->addLink('http://test.com'); - $textrun->addImage($imageSrc, array('align' => 'top')); + $textrun->addImage($imageSrc, array('align' => 'center')); $textrun->addFootnote(); $doc = TestHelperDOCX::getDocument($phpWord); @@ -497,6 +505,10 @@ class DocumentTest extends \PHPUnit_Framework_TestCase $table->addCell(40); $table->addCell(40); + $table->addRow(); + $cell = $table->addCell(200, array('borderRightColor' => 'FF0000')); + $cell->getStyle()->setGridSpan(5); + $doc = TestHelperDOCX::getDocument($phpWord); $element = $doc->getElement('/w:document/w:body/w:tbl/w:tr/w:tc/w:tcPr/w:gridSpan'); diff --git a/tests/PhpWord/Tests/Writer/Word2007/Part/StylesTest.php b/tests/PhpWord/Tests/Writer/Word2007/Part/StylesTest.php index 795d3e8a..103caa81 100644 --- a/tests/PhpWord/Tests/Writer/Word2007/Part/StylesTest.php +++ b/tests/PhpWord/Tests/Writer/Word2007/Part/StylesTest.php @@ -49,22 +49,19 @@ class StylesTest extends \PHPUnit_Framework_TestCase $rStyle = array('size' => 20); $tStyle = array( 'bgColor' => 'FF0000', - 'cellMarginTop' => 120, - 'cellMarginBottom' => 120, - 'cellMarginLeft' => 120, - 'cellMarginRight' => 120, - 'borderTopSize' => 120, - 'borderBottomSize' => 120, - 'borderLeftSize' => 120, - 'borderRightSize' => 120, - 'borderInsideHSize' => 120, - 'borderInsideVSize' => 120, + 'cellMargin' => 120, + 'borderSize' => 120, + ); + $firstRowStyle = array( + 'bgColor' => '0000FF', + 'borderSize' => 120, + 'borderColor' => '00FF00', ); $phpWord->setDefaultParagraphStyle($pStyle); $phpWord->addParagraphStyle('Base Style', $pBase); $phpWord->addParagraphStyle('New Style', $pNew); $phpWord->addFontStyle('New Style', $rStyle, $pStyle); - $phpWord->addTableStyle('Table Style', $tStyle, $tStyle); + $phpWord->addTableStyle('Table Style', $tStyle, $firstRowStyle); $phpWord->addTitleStyle(1, $rStyle, $pStyle); $doc = TestHelperDOCX::getDocument($phpWord); diff --git a/tests/PhpWord/Tests/Writer/Word2007/PartTest.php b/tests/PhpWord/Tests/Writer/Word2007/PartTest.php new file mode 100644 index 00000000..c3d29331 --- /dev/null +++ b/tests/PhpWord/Tests/Writer/Word2007/PartTest.php @@ -0,0 +1,41 @@ +setMedia(array(array('type' => '', 'target' => ''))); + $object->write(); + } +} diff --git a/tests/PhpWord/Tests/Writer/Word2007/StyleTest.php b/tests/PhpWord/Tests/Writer/Word2007/StyleTest.php index 97a6c6bd..cc722efb 100644 --- a/tests/PhpWord/Tests/Writer/Word2007/StyleTest.php +++ b/tests/PhpWord/Tests/Writer/Word2007/StyleTest.php @@ -29,8 +29,8 @@ class StyleTest extends \PHPUnit_Framework_TestCase public function testEmptyStyles() { $styles = array( - 'Cell', 'Font', 'Image', 'Indentation', 'LineNumbering', - 'Paragraph', 'Section', 'Shading', 'Spacing', 'Tab', 'Table', 'TextBox' + 'Alignment', 'Cell', 'Font', 'Image', 'Indentation', 'LineNumbering', + 'Paragraph', 'Row', 'Section', 'Shading', 'Spacing', 'Tab', 'Table', 'TextBox' ); foreach ($styles as $style) { $objectClass = 'PhpOffice\\PhpWord\\Writer\\Word2007\\Style\\' . $style; diff --git a/tests/PhpWord/Tests/Writer/Word2007Test.php b/tests/PhpWord/Tests/Writer/Word2007Test.php index 5ca5759c..db6e5cad 100644 --- a/tests/PhpWord/Tests/Writer/Word2007Test.php +++ b/tests/PhpWord/Tests/Writer/Word2007Test.php @@ -122,18 +122,6 @@ class Word2007Test extends \PHPUnit_Framework_TestCase unlink($file); } - /** - * Save with no PhpWord object assigned - * - * @expectedException \PhpOffice\PhpWord\Exception\Exception - * @expectedExceptionMessage PhpWord object unassigned. - */ - public function testSaveException() - { - $writer = new Word2007(); - $writer->save(); - } - /** * Check content types */