Merge branch 'develop' into add-getVariableCount-method

This commit is contained in:
troosan 2018-12-11 21:31:18 +01:00 committed by GitHub
commit b188ab94e1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
42 changed files with 501 additions and 59 deletions

1
.gitignore vendored
View File

@ -18,6 +18,7 @@ vendor
/.settings
phpword.ini
/.buildpath
/.scannerwork
/.project
/nbproject
/.php_cs.cache

View File

@ -10,11 +10,22 @@ php:
- 7.0
- 7.1
- 7.2
- 7.3
matrix:
include:
- php: 7.0
env: COVERAGE=1
- php: 5.3
env: COMPOSER_MEMORY_LIMIT=2G
- php: 7.3
env: DEPENDENCIES="--ignore-platform-reqs"
exclude:
- php: 5.3
- php: 7.0
- php: 7.3
allow_failures:
- php: 7.3
cache:
directories:
@ -32,10 +43,10 @@ before_install:
before_script:
## Deactivate xdebug if we don't do code coverage
- if [ -z "$COVERAGE" ]; then phpenv config-rm xdebug.ini ; fi
- if [ -z "$COVERAGE" ]; then phpenv config-rm xdebug.ini || echo "xdebug not available" ; fi
## Composer
- composer self-update
- travis_wait composer install --prefer-source
- travis_wait composer install --prefer-source $(if [ -n "$DEPENDENCIES" ]; then echo $DEPENDENCIES; fi)
## PHPDocumentor
##- mkdir -p build/docs
- mkdir -p build/coverage

View File

@ -3,14 +3,23 @@ Change Log
All notable changes to this project will be documented in this file.
This project adheres to [Semantic Versioning](http://semver.org/).
v0.16.0 (xx xxx 2018)
v0.16.0 (xx dec 2018)
----------------------
### Added
- Add getVariableCount method in TemplateProcessor. @nicoder #1272
- Add setting Chart Title and Legend visibility @Tom-Magill #1433
- Add ability to pass a Style object in Section constructor @ndench #1416
- Add support for hidden text @Alexmg86 #1527
### Fixed
- Fix regex in `cloneBlock` function @nicoder #1269
- HTML Title Writer loses text when Title contains a TextRun instead a string. @begnini #1436
- Fix regex in fixBrokenMacros, make it less greedy @MuriloSo @brainwood @yurii-sio2 #1502 #1345
- 240 twips are being added to line spacing, should not happen when using lineRule fixed @troosan #1509 #1505
- Adding table layout to the generated HTML @aarangara #1441
- Fix loading of Sharepoint document @Garrcomm #1498
- RTF writer: Round getPageSizeW and getPageSizeH to avoid decimals @Patrick64 #1493
- Fix parsing of Office 365 documents @Timanx #1485
v0.15.0 (14 Jul 2018)
----------------------

View File

@ -161,7 +161,7 @@ $objWriter->save('helloWorld.html');
```
More examples are provided in the [samples folder](samples/). For an easy access to those samples launch `php -S localhost:8000` in the samples directory then browse to [http://localhost:8000](http://localhost:8000) to view the samples.
You can also read the [Developers' Documentation](http://phpword.readthedocs.org/) and the [API Documentation](http://phpoffice.github.io/PHPWord/docs/master/) for more detail.
You can also read the [Developers' Documentation](http://phpword.readthedocs.org/) for more detail.
## Contributing

View File

@ -45,7 +45,7 @@
"php-cs-fixer fix --ansi --dry-run --diff",
"phpcs --report-width=200 --report-summary --report-full samples/ src/ tests/ --ignore=src/PhpWord/Shared/PCLZip --standard=PSR2 -n",
"phpmd src/,tests/ text ./phpmd.xml.dist --exclude pclzip.lib.php",
"@test"
"@test-no-coverage"
],
"fix": [
"php-cs-fixer fix --ansi"

View File

@ -8,4 +8,4 @@ Fixes # (issue)
- [ ] I have run `composer run-script check --timeout=0` and no errors were reported
- [ ] The new code is covered by unit tests (check build/coverage for coverage report)
- [ ] I have update the documentation to describe the changes
- [ ] I have updated the documentation to describe the changes

View File

@ -29,6 +29,7 @@ Available Section style options:
- ``marginRight``. Page margin right in *twip*.
- ``marginBottom``. Page margin bottom in *twip*.
- ``orientation``. Page orientation (``portrait``, which is default, or ``landscape``).
See ``\PhpOffice\PhpWord\Style\Section::ORIENTATION_...`` class constants for possible values
- ``pageSizeH``. Page height in *twip*. Implicitly defined by ``orientation`` option. Any changes are discouraged.
- ``pageSizeW``. Page width in *twip*. Implicitly defined by ``orientation`` option. Any changes are discouraged.
@ -45,7 +46,7 @@ Available Font style options:
- ``color``. Font color, e.g. *FF0000*.
- ``doubleStrikethrough``. Double strikethrough, *true* or *false*.
- ``fgColor``. Font highlight color, e.g. *yellow*, *green*, *blue*.
See ``\PhpOffice\PhpWord\Style\Font::FGCOLOR_...`` constants for more values
See ``\PhpOffice\PhpWord\Style\Font::FGCOLOR_...`` class constants for possible values
- ``hint``. Font content type, *default*, *eastAsia*, or *cs*.
- ``italic``. Italic, *true* or *false*.
- ``name``. Font name, e.g. *Arial*.
@ -56,10 +57,11 @@ Available Font style options:
- ``subScript``. Subscript, *true* or *false*.
- ``superScript``. Superscript, *true* or *false*.
- ``underline``. Underline, *single*, *dash*, *dotted*, etc.
See ``\PhpOffice\PhpWord\Style\Font::UNDERLINE_...`` constants for more values
See ``\PhpOffice\PhpWord\Style\Font::UNDERLINE_...`` class constants for possible values
- ``lang``. Language, either a language code like *en-US*, *fr-BE*, etc. or an object (or as an array) if you need to set eastAsian or bidirectional languages
See ``\PhpOffice\PhpWord\Style\Language`` class for some language codes.
- ``position``. The text position, raised or lowered, in half points
- ``hidden``. Hidden text, *true* or *false*.
.. _paragraph-style:
@ -69,7 +71,7 @@ Paragraph
Available Paragraph style options:
- ``alignment``. Supports all alignment modes since 1st Edition of ECMA-376 standard up till ISO/IEC 29500:2012.
See ``\PhpOffice\PhpWord\SimpleType\Jc`` class for the details.
See ``\PhpOffice\PhpWord\SimpleType\Jc`` class constants for possible values.
- ``basedOn``. Parent style.
- ``hanging``. Hanging in *twip*.
- ``indent``. Indent in *twip*.
@ -80,8 +82,9 @@ Available Paragraph style options:
- ``pageBreakBefore``. Start paragraph on next page, *true* or *false*.
- ``spaceBefore``. Space before paragraph in *twip*.
- ``spaceAfter``. Space after paragraph in *twip*.
- ``spacing``. Space between lines.
- ``spacing``. Space between lines in *twip*. If spacingLineRule is auto, 240 (height of 1 line) will be added, so if you want a double line height, set this to 240.
- ``spacingLineRule``. Line Spacing Rule. *auto*, *exact*, *atLeast*
See ``\PhpOffice\PhpWord\SimpleType\LineSpacingRule`` class constants for possible values.
- ``suppressAutoHyphens``. Hyphenation for paragraph, *true* or *false*.
- ``tabs``. Set of custom tab stops.
- ``widowControl``. Allow first/last line to display on a separate page, *true* or *false*.
@ -89,7 +92,7 @@ Available Paragraph style options:
- ``bidi``. Right to Left Paragraph Layout, *true* or *false*.
- ``shading``. Paragraph Shading.
- ``textAlignment``. Vertical Character Alignment on Line.
See ``\PhpOffice\PhpWord\SimpleType\TextAlignment`` class for possible values.
See ``\PhpOffice\PhpWord\SimpleType\TextAlignment`` class constants for possible values.
.. _table-style:
@ -99,7 +102,7 @@ Table
Available Table style options:
- ``alignment``. Supports all alignment modes since 1st Edition of ECMA-376 standard up till ISO/IEC 29500:2012.
See ``\PhpOffice\PhpWord\SimpleType\JcTable`` and ``\PhpOffice\PhpWord\SimpleType\Jc`` classes for the details.
See ``\PhpOffice\PhpWord\SimpleType\JcTable`` and ``\PhpOffice\PhpWord\SimpleType\Jc`` class constants for possible values.
- ``bgColor``. Background color, e.g. '9966CC'.
- ``border(Top|Right|Bottom|Left)Color``. Border color, e.g. '9966CC'.
- ``border(Top|Right|Bottom|Left)Size``. Border size in *twip*.
@ -168,7 +171,7 @@ Numbering level
Available NumberingLevel style options:
- ``alignment``. Supports all alignment modes since 1st Edition of ECMA-376 standard up till ISO/IEC 29500:2012.
See ``\PhpOffice\PhpWord\SimpleType\Jc`` class for the details.
See ``\PhpOffice\PhpWord\SimpleType\Jc`` class constants for possible values.
- ``font``. Font name.
- ``format``. Numbering format bullet\|decimal\|upperRoman\|lowerRoman\|upperLetter\|lowerLetter.
- ``hanging``. See paragraph style.
@ -190,6 +193,14 @@ Available Chart style options:
- ``width``. Width (in EMU).
- ``height``. Height (in EMU).
- ``3d``. Is 3D; applies to pie, bar, line, area, *true* or *false*.
- ``colors``. A list of colors to use in the chart.
- ``title``. The title for the chart.
- ``showLegend``. Show legend, *true* or *false*.
- ``categoryLabelPosition``. Label position for categories, *nextTo* (default), *low* or *high*.
- ``valueLabelPosition``. Label position for values, *nextTo* (default), *low* or *high*.
- ``categoryAxisTitle``. The title for the category axis.
- ``valueAxisTitle``. The title for the values axis.
- ``majorTickMarkPos``. The position for major tick marks, *in*, *out*, *cross*, *none* (default).
- ``showAxisLabels``. Show labels for axis, *true* or *false*.
- ``gridX``. Show Gridlines for X-Axis, *true* or *false*.
- ``gridY``. Show Gridlines for Y-Axis, *true* or *false*.

View File

@ -23,5 +23,6 @@
<logging>
<log type="coverage-html" target="./build/coverage" />
<log type="coverage-clover" target="./build/logs/clover.xml" />
<log type="junit" target="./build/logs/logfile.xml"/>
</logging>
</phpunit>

View File

@ -39,6 +39,9 @@ $textrun->addText(' Sample Object: ');
$textrun->addObject('resources/_sheet.xls');
$textrun->addText(' Here is some more text. ');
$textrun = $section->addTextRun();
$textrun->addText('This text is not visible.', array('hidden' => true));
// Save file
echo write($phpWord, basename(__FILE__, '.php'), $writers);
if (!CLI) {

View File

@ -89,6 +89,9 @@ $html .= '<table align="center" style="width: 80%; border: 6px #0000FF double;">
<tr><td style="text-align: center;">Cell in parent table</td></tr>
</table>';
$html .= '<p style="margin-top: 240pt;">The text below is not visible, click on show/hide to reveil it:</p>';
$html .= '<p style="display: none">This is hidden text</p>';
\PhpOffice\PhpWord\Shared\Html::addHtml($section, $html, false, false);
// Save file

17
sonar-project.properties Normal file
View File

@ -0,0 +1,17 @@
# must be unique in a given SonarQube instance
sonar.projectKey=phpoffice:phpword
# this is the name and version displayed in the SonarQube UI. Was mandatory prior to SonarQube 6.1.
sonar.projectName=PHPWord
sonar.projectVersion=0.16
# Path is relative to the sonar-project.properties file. Replace "\" by "/" on Windows.
# This property is optional if sonar.modules is set.
sonar.sources=src
sonar.tests=tests
sonar.php.coverage.reportPaths=build/logs/clover.xml
sonar.php.tests.reportPath=build/logs/logfile.xml
# Encoding of the source code. Default is default system encoding
#sonar.sourceEncoding=UTF-8
sonar.host.url=http://localhost:9000

View File

@ -59,14 +59,16 @@ class Section extends AbstractContainer
* Create new instance
*
* @param int $sectionCount
* @param array $style
* @param null|array|\PhpOffice\PhpWord\Style $style
*/
public function __construct($sectionCount, $style = null)
{
$this->sectionId = $sectionCount;
$this->setDocPart($this->container, $this->sectionId);
$this->style = new SectionStyle();
$this->setStyle($style);
if (null === $style) {
$style = new SectionStyle();
}
$this->style = $this->setNewStyle(new SectionStyle(), $style);
}
/**

View File

@ -2185,6 +2185,8 @@ class MsDoc extends AbstractReader implements ReaderInterface
$sprmCPicLocation += $embeddedBlipRH['recLen'];
break;
case self::OFFICEARTBLIPPNG:
break;
default:
// print_r(dechex($embeddedBlipRH['recType']));
}

View File

@ -62,6 +62,9 @@ class Word2007 extends AbstractReader implements ReaderInterface
foreach ($steps as $step) {
$stepPart = $step['stepPart'];
$stepItems = $step['stepItems'];
if (!isset($relationships[$stepPart])) {
continue;
}
foreach ($relationships[$stepPart] as $relItem) {
$relType = $relItem['type'];
if (isset($stepItems[$relType])) {

View File

@ -444,6 +444,7 @@ abstract class AbstractPart
'rtl' => array(self::READ_TRUE, 'w:rtl'),
'lang' => array(self::READ_VALUE, 'w:lang'),
'position' => array(self::READ_VALUE, 'w:position'),
'hidden' => array(self::READ_TRUE, 'w:vanish'),
);
return $this->readStyleDefs($xmlReader, $styleNode, $styleDefs);

View File

@ -68,6 +68,7 @@ class Styles extends AbstractPart
if (is_null($name)) {
$name = $xmlReader->getAttribute('w:val', $node, 'w:name');
}
$headingMatches = array();
preg_match('/Heading(\d)/', $name, $headingMatches);
// $default = ($xmlReader->getAttribute('w:default', $node) == 1);
switch ($type) {

View File

@ -23,6 +23,7 @@ use PhpOffice\PhpWord\Element\Table;
use PhpOffice\PhpWord\Settings;
use PhpOffice\PhpWord\SimpleType\Jc;
use PhpOffice\PhpWord\SimpleType\NumberFormat;
use PhpOffice\PhpWord\Style\Paragraph;
/**
* Common Html functions
@ -514,6 +515,9 @@ class Html
case 'text-align':
$styles['alignment'] = self::mapAlign($cValue);
break;
case 'display':
$styles['hidden'] = $cValue === 'none';
break;
case 'direction':
$styles['rtl'] = $cValue === 'rtl';
break;
@ -531,18 +535,27 @@ class Html
$styles['bgColor'] = trim($cValue, '#');
break;
case 'line-height':
$matches = array();
if (preg_match('/([0-9]+\.?[0-9]*[a-z]+)/', $cValue, $matches)) {
//matches number with a unit, e.g. 12px, 15pt, 20mm, ...
$spacingLineRule = \PhpOffice\PhpWord\SimpleType\LineSpacingRule::EXACT;
$spacing = Converter::cssToTwip($matches[1]) / \PhpOffice\PhpWord\Style\Paragraph::LINE_HEIGHT;
$spacing = Converter::cssToTwip($matches[1]);
} elseif (preg_match('/([0-9]+)%/', $cValue, $matches)) {
//matches percentages
$spacingLineRule = \PhpOffice\PhpWord\SimpleType\LineSpacingRule::AUTO;
$spacing = ((int) $matches[1]) / 100;
//we are subtracting 1 line height because the Spacing writer is adding one line
$spacing = ((((int) $matches[1]) / 100) * Paragraph::LINE_HEIGHT) - Paragraph::LINE_HEIGHT;
} else {
//any other, wich is a multiplier. E.g. 1.2
$spacingLineRule = \PhpOffice\PhpWord\SimpleType\LineSpacingRule::AUTO;
$spacing = $cValue;
//we are subtracting 1 line height because the Spacing writer is adding one line
$spacing = ($cValue * Paragraph::LINE_HEIGHT) - Paragraph::LINE_HEIGHT;
}
$styles['spacingLineRule'] = $spacingLineRule;
$styles['lineHeight'] = $spacing;
$styles['line-spacing'] = $spacing;
break;
case 'letter-spacing':
$styles['letter-spacing'] = Converter::cssToTwip($cValue);
break;
case 'text-indent':
$styles['indentation']['firstLine'] = Converter::cssToTwip($cValue);
@ -743,8 +756,6 @@ class Html
default:
return Jc::START;
}
return null;
}
/**

View File

@ -52,6 +52,20 @@ class Chart extends AbstractStyle
*/
private $colors = array();
/**
* Chart title
*
* @var string
*/
private $title = null;
/**
* Chart legend visibility
*
* @var bool
*/
private $showLegend = false;
/**
* A list of display options for data labels
*
@ -97,9 +111,15 @@ class Chart extends AbstractStyle
*/
private $valueAxisTitle;
/**
* The position for major tick marks
* Possible values are 'in', 'out', 'cross', 'none'
*
* @var string
*/
private $majorTickMarkPos = 'none';
/*
/**
* Show labels for axis
*
* @var bool
@ -221,6 +241,50 @@ class Chart extends AbstractStyle
return $this;
}
/**
* Get the chart title
*
* @return string
*/
public function getTitle()
{
return $this->title;
}
/**
* Set the chart title
*
* @param string $value
*/
public function setTitle($value = null)
{
$this->title = $value;
return $this;
}
/**
* Get chart legend visibility
*
* @return bool
*/
public function isShowLegend()
{
return $this->showLegend;
}
/**
* Set chart legend visibility
*
* @param bool $value
*/
public function setShowLegend($value = false)
{
$this->showLegend = $value;
return $this;
}
/*
* Show labels for axis
*
@ -394,8 +458,8 @@ class Chart extends AbstractStyle
}
/**
* set the position for major tick marks
* @param string $position [description]
* Set the position for major tick marks
* @param string $position
*/
public function setMajorTickPosition($position)
{
@ -403,7 +467,7 @@ class Chart extends AbstractStyle
$this->majorTickMarkPos = $this->setEnumVal($position, $enum, $this->majorTickMarkPos);
}
/*
/**
* Show Gridlines for X-Axis
*
* @return bool

View File

@ -80,7 +80,7 @@ class Font extends AbstractStyle
*
* @var array
*/
protected $aliases = array('line-height' => 'lineHeight');
protected $aliases = array('line-height' => 'lineHeight', 'letter-spacing' => 'spacing');
/**
* Font style type
@ -252,6 +252,14 @@ class Font extends AbstractStyle
*/
private $lang;
/**
* Hidden text
*
* @var bool
* @see http://www.datypic.com/sc/ooxml/e-w_vanish-1.html
*/
private $hidden = false;
/**
* Vertically Raised or Lowered Text
*
@ -299,6 +307,7 @@ class Font extends AbstractStyle
'smallCaps' => $this->isSmallCaps(),
'allCaps' => $this->isAllCaps(),
'fgColor' => $this->getFgColor(),
'hidden' => $this->isHidden(),
),
'spacing' => array(
'scale' => $this->getScale(),
@ -938,6 +947,29 @@ class Font extends AbstractStyle
return $this->getParagraph();
}
/**
* Get hidden text
*
* @return bool
*/
public function isHidden()
{
return $this->hidden;
}
/**
* Set hidden text
*
* @param bool $value
* @return self
*/
public function setHidden($value = true)
{
$this->hidden = $this->setBoolVal($value, $this->hidden);
return $this;
}
/**
* Get position
*

View File

@ -65,6 +65,12 @@ final class Language extends AbstractStyle
const PT_BR = 'pt-BR';
const PT_BR_ID = 1046;
const NL_NL = 'nl-NL';
const NL_NL_ID = 1043;
const UK_UA = 'uk-UA';
const UK_UA_ID = 1058;
/**
* Language ID, used for RTF document generation
*

View File

@ -61,7 +61,7 @@ class Paragraph extends Border
*
* @var array
*/
protected $aliases = array('line-height' => 'lineHeight');
protected $aliases = array('line-height' => 'lineHeight', 'line-spacing' => 'spacing');
/**
* Parent style
@ -199,8 +199,6 @@ class Paragraph extends Border
$key = Text::removeUnderscorePrefix($key);
if ('indent' == $key || 'hanging' == $key) {
$value = $value * 720;
} elseif ('spacing' == $key) {
$value += 240; // because line height of 1 matches 240 twips
}
return parent::setStyleValue($key, $value);
@ -479,7 +477,7 @@ class Paragraph extends Border
/**
* Get spacing between lines
*
* @return int
* @return int|float
*/
public function getSpacing()
{
@ -489,7 +487,7 @@ class Paragraph extends Border
/**
* Set spacing between lines
*
* @param int $value
* @param int|float $value
* @return self
*/
public function setSpacing($value = null)
@ -547,7 +545,8 @@ class Paragraph extends Border
}
$this->lineHeight = $lineHeight;
$this->setSpacing($lineHeight * self::LINE_HEIGHT);
$this->setSpacing(($lineHeight - 1) * self::LINE_HEIGHT);
$this->setSpacingLineRule(\PhpOffice\PhpWord\SimpleType\LineSpacingRule::AUTO);
return $this;
}

View File

@ -217,10 +217,10 @@ class TemplateProcessor
if (is_array($replace)) {
foreach ($replace as &$item) {
$item = self::ensureUtf8Encoded($item);
$item = static::ensureUtf8Encoded($item);
}
} else {
$replace = self::ensureUtf8Encoded($replace);
$replace = static::ensureUtf8Encoded($replace);
}
if (Settings::isOutputEscapingEnabled()) {
@ -458,17 +458,13 @@ class TemplateProcessor
*/
protected function fixBrokenMacros($documentPart)
{
$fixedDocumentPart = $documentPart;
$fixedDocumentPart = preg_replace_callback(
'|\$[^{]*\{[^}]*\}|U',
return preg_replace_callback(
'/\$(?:\{|[^{$]*\>\{)[^}$]*\}/U',
function ($match) {
return strip_tags($match[0]);
},
$fixedDocumentPart
$documentPart
);
return $fixedDocumentPart;
}
/**
@ -519,11 +515,19 @@ class TemplateProcessor
}
/**
* Usually, the name of main part document will be 'document.xml'. However, some .docx files (possibly those from Office 365, experienced also on documents from Word Online created from blank templates) have file 'document22.xml' in their zip archive instead of 'document.xml'. This method searches content types file to correctly determine the file name.
*
* @return string
*/
protected function getMainPartName()
{
return 'word/document.xml';
$contentTypes = $this->zipClass->getFromName('[Content_Types].xml');
$pattern = '~PartName="\/(word\/document.*?\.xml)" ContentType="application\/vnd\.openxmlformats-officedocument\.wordprocessingml\.document\.main\+xml"~';
preg_match($pattern, $contentTypes, $matches);
return array_key_exists(1, $matches) ? $matches[1] : 'word/document.xml';
}
/**

View File

@ -39,7 +39,8 @@ class Table extends AbstractElement
$rows = $this->element->getRows();
$rowCount = count($rows);
if ($rowCount > 0) {
$content .= '<table>' . PHP_EOL;
$content .= '<table' . self::getTableStyle($this->element->getStyle()) . '>' . PHP_EOL;
for ($i = 0; $i < $rowCount; $i++) {
/** @var $row \PhpOffice\PhpWord\Element\Row Type hint */
$rowStyle = $rows[$i]->getStyle();
@ -102,4 +103,25 @@ class Table extends AbstractElement
return $content;
}
/**
* Translates Table style in CSS equivalent
*
* @param \PhpOffice\PhpWord\Style\Table|null $tableStyle
* @return string
*/
private function getTableStyle(\PhpOffice\PhpWord\Style\Table $tableStyle = null)
{
if ($tableStyle == null) {
return '';
}
$style = ' style="';
if ($tableStyle->getLayout() == \PhpOffice\PhpWord\Style\Table::LAYOUT_FIXED) {
$style .= 'table-layout: fixed;';
} elseif ($tableStyle->getLayout() == \PhpOffice\PhpWord\Style\Table::LAYOUT_AUTO) {
$style .= 'table-layout: auto;';
}
return $style . '"';
}
}

View File

@ -60,6 +60,7 @@ class Font extends AbstractStyle
$css['text-decoration'] .= $this->getValueIf($lineThrough, 'line-through ');
$css['text-transform'] = $this->getValueIf($style->isAllCaps(), 'uppercase');
$css['font-variant'] = $this->getValueIf($style->isSmallCaps(), 'small-caps');
$css['display'] = $this->getValueIf($style->isHidden(), 'none');
$spacing = $style->getSpacing();
$css['letter-spacing'] = $this->getValueIf(!is_null($spacing), ($spacing / 20) . 'pt');

View File

@ -75,6 +75,9 @@ class Font extends AbstractStyle
$xmlWriter->writeAttributeIf($style->isSmallCaps(), 'fo:font-variant', 'small-caps');
$xmlWriter->writeAttributeIf($style->isAllCaps(), 'fo:text-transform', 'uppercase');
//Hidden text
$xmlWriter->writeAttributeIf($style->isHidden(), 'text:display', 'none');
// Superscript/subscript
$xmlWriter->writeAttributeIf($style->isSuperScript(), 'style:text-position', 'super');
$xmlWriter->writeAttributeIf($style->isSubScript(), 'style:text-position', 'sub');

View File

@ -43,8 +43,8 @@ class Section extends AbstractStyle
$content .= '\sectd ';
// Size & margin
$content .= $this->getValueIf($style->getPageSizeW() !== null, '\pgwsxn' . $style->getPageSizeW());
$content .= $this->getValueIf($style->getPageSizeH() !== null, '\pghsxn' . $style->getPageSizeH());
$content .= $this->getValueIf($style->getPageSizeW() !== null, '\pgwsxn' . round($style->getPageSizeW()));
$content .= $this->getValueIf($style->getPageSizeH() !== null, '\pghsxn' . round($style->getPageSizeH()));
$content .= ' ';
$content .= $this->getValueIf($style->getMarginTop() !== null, '\margtsxn' . $style->getMarginTop());
$content .= $this->getValueIf($style->getMarginRight() !== null, '\margrsxn' . $style->getMarginRight());

View File

@ -103,7 +103,9 @@ class Image extends AbstractElement
$style->setPositioning('absolute');
$styleWriter = new ImageStyleWriter($xmlWriter, $style);
$xmlWriter->startElement('w:p');
if (!$this->withoutP) {
$xmlWriter->startElement('w:p');
}
$xmlWriter->startElement('w:r');
$xmlWriter->startElement('w:pict');
$xmlWriter->startElement('v:shape');
@ -118,6 +120,8 @@ class Image extends AbstractElement
$xmlWriter->endElement(); // v:shape
$xmlWriter->endElement(); // w:pict
$xmlWriter->endElement(); // w:r
$xmlWriter->endElement(); // w:p
if (!$this->withoutP) {
$xmlWriter->endElement(); // w:p
}
}
}

View File

@ -105,8 +105,6 @@ class Chart extends AbstractPart
{
$xmlWriter->startElement('c:chart');
$xmlWriter->writeElementBlock('c:autoTitleDeleted', 'val', 1);
$this->writePlotArea($xmlWriter);
$xmlWriter->endElement(); // c:chart
@ -131,6 +129,34 @@ class Chart extends AbstractPart
$style = $this->element->getStyle();
$this->options = $this->types[$type];
$title = $style->getTitle();
$showLegend = $style->isShowLegend();
//Chart title
if ($title) {
$xmlWriter->startElement('c:title');
$xmlWriter->startElement('c:tx');
$xmlWriter->startElement('c:rich');
$xmlWriter->writeRaw('
<a:bodyPr/>
<a:lstStyle/>
<a:p>
<a:pPr>
<a:defRPr/></a:pPr><a:r><a:rPr/><a:t>' . $title . '</a:t></a:r>
<a:endParaRPr/>
</a:p>');
$xmlWriter->endElement(); // c:rich
$xmlWriter->endElement(); // c:tx
$xmlWriter->endElement(); // c:title
} else {
$xmlWriter->writeElementBlock('c:autoTitleDeleted', 'val', 1);
}
//Chart legend
if ($showLegend) {
$xmlWriter->writeRaw('<c:legend><c:legendPos val="r"/></c:legend>');
}
$xmlWriter->startElement('c:plotArea');
$xmlWriter->writeElement('c:layout');

View File

@ -120,6 +120,9 @@ class Font extends AbstractStyle
$xmlWriter->writeElementIf($style->isSmallCaps(), 'w:smallCaps');
$xmlWriter->writeElementIf($style->isAllCaps(), 'w:caps');
//Hidden text
$xmlWriter->writeElementIf($style->isHidden(), 'w:vanish');
// Underline
$xmlWriter->writeElementIf($style->getUnderline() != 'none', 'w:u', 'w:val', $style->getUnderline());

View File

@ -61,6 +61,7 @@ class Frame extends AbstractStyle
'hPos' => 'mso-position-horizontal',
'vPos' => 'mso-position-vertical',
'hPosRelTo' => 'mso-position-horizontal-relative',
'vPosRelTo' => 'mso-position-vertical-relative',
);
$posStyles = $this->getStyles($style, $properties);

View File

@ -44,6 +44,10 @@ class Spacing extends AbstractStyle
$xmlWriter->writeAttributeIf(!is_null($after), 'w:after', $this->convertTwip($after));
$line = $style->getLine();
//if linerule is auto, the spacing is supposed to include the height of the line itself, which is 240 twips
if (null !== $line && 'auto' === $style->getLineRule()) {
$line += \PhpOffice\PhpWord\Style\Paragraph::LINE_HEIGHT;
}
$xmlWriter->writeAttributeIf(!is_null($line), 'w:line', $line);
$xmlWriter->writeAttributeIf(!is_null($line), 'w:lineRule', $style->getLineRule());

View File

@ -19,6 +19,7 @@ namespace PhpOffice\PhpWord\Element;
use PhpOffice\PhpWord\PhpWord;
use PhpOffice\PhpWord\Style;
use PhpOffice\PhpWord\Style\Section as SectionStyle;
/**
* @covers \PhpOffice\PhpWord\Element\Section
@ -27,6 +28,27 @@ use PhpOffice\PhpWord\Style;
*/
class SectionTest extends \PHPUnit\Framework\TestCase
{
public function testConstructorWithDefaultStyle()
{
$section = new Section(0);
$this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Section', $section->getStyle());
}
public function testConstructorWithArrayStyle()
{
$section = new Section(0, array('orientation' => 'landscape'));
$style = $section->getStyle();
$this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Section', $style);
$this->assertEquals('landscape', $style->getOrientation());
}
public function testConstructorWithObjectStyle()
{
$style = new SectionStyle();
$section = new Section(0, $style);
$this->assertSame($style, $section->getStyle());
}
/**
* @covers ::setStyle
*/

View File

@ -145,4 +145,28 @@ class StyleTest extends AbstractTestReader
$this->assertSame(TblWidth::TWIP, $tableStyle->getIndent()->getType());
$this->assertSame(2160, $tableStyle->getIndent()->getValue());
}
public function testReadHidden()
{
$documentXml = '<w:p>
<w:r>
<w:rPr>
<w:vanish/>
</w:rPr>
<w:t xml:space="preserve">This text is hidden</w:t>
</w:r>
</w:p>';
$phpWord = $this->getDocumentFromString(array('document' => $documentXml));
$elements = $phpWord->getSection(0)->getElements();
/** @var \PhpOffice\PhpWord\Element\TextRun $elements */
$textRun = $elements[0];
$this->assertInstanceOf('PhpOffice\PhpWord\Element\TextRun', $textRun);
$this->assertInstanceOf('PhpOffice\PhpWord\Element\Text', $textRun->getElement(0));
$this->assertInstanceOf('PhpOffice\PhpWord\Style\Font', $textRun->getElement(0)->getFontStyle());
/** @var \PhpOffice\PhpWord\Style\Font $fontStyle */
$fontStyle = $textRun->getElement(0)->getFontStyle();
$this->assertTrue($fontStyle->isHidden());
}
}

View File

@ -86,6 +86,21 @@ class HtmlTest extends \PHPUnit\Framework\TestCase
$this->assertCount(2, $section->getElements());
}
/**
* Test HTML entities
*/
public function testParseHtmlEntities()
{
\PhpOffice\PhpWord\Settings::setOutputEscapingEnabled(true);
$phpWord = new \PhpOffice\PhpWord\PhpWord();
$section = $phpWord->addSection();
Html::addHtml($section, 'text with entities &lt;my text&gt;');
$doc = TestHelperDOCX::getDocument($phpWord, 'Word2007');
$this->assertTrue($doc->elementExists('/w:document/w:body/w:p[1]/w:r/w:t'));
$this->assertEquals('text with entities <my text>', $doc->getElement('/w:document/w:body/w:p[1]/w:r/w:t')->nodeValue);
}
/**
* Test underline
*/

View File

@ -76,6 +76,7 @@ class FontTest extends \PHPUnit\Framework\TestCase
'spacing' => null,
'kerning' => null,
'lang' => null,
'hidden' => false,
);
foreach ($attributes as $key => $default) {
$get = is_bool($default) ? "is{$key}" : "get{$key}";
@ -117,6 +118,7 @@ class FontTest extends \PHPUnit\Framework\TestCase
'rtl' => true,
'noProof' => true,
'lang' => new Language(Language::EN_US),
'hidden' => true,
);
$object->setStyleByArray($attributes);
foreach ($attributes as $key => $value) {

View File

@ -91,8 +91,6 @@ class ParagraphTest extends \PHPUnit\Framework\TestCase
$object->setStyleValue("$key", $value);
if ('indent' == $key || 'hanging' == $key) {
$value = $value * 720;
} elseif ('spacing' == $key) {
$value += 240;
}
$this->assertEquals($value, $object->$get());
}

View File

@ -315,4 +315,45 @@ final class TemplateProcessorTest extends \PHPUnit\Framework\TestCase
);
}
}
/**
* Template macros can be fixed.
*
* @covers ::fixBrokenMacros
* @test
*/
public function testFixBrokenMacros()
{
$templateProcessor = new TestableTemplateProcesor();
$fixed = $templateProcessor->fixBrokenMacros('<w:r><w:t>normal text</w:t></w:r>');
$this->assertEquals('<w:r><w:t>normal text</w:t></w:r>', $fixed);
$fixed = $templateProcessor->fixBrokenMacros('<w:r><w:t>${documentContent}</w:t></w:r>');
$this->assertEquals('<w:r><w:t>${documentContent}</w:t></w:r>', $fixed);
$fixed = $templateProcessor->fixBrokenMacros('<w:r><w:t>$</w:t><w:t>{documentContent}</w:t></w:r>');
$this->assertEquals('<w:r><w:t>${documentContent}</w:t></w:r>', $fixed);
$fixed = $templateProcessor->fixBrokenMacros('<w:r><w:t>$1500</w:t><w:t>${documentContent}</w:t></w:r>');
$this->assertEquals('<w:r><w:t>$1500</w:t><w:t>${documentContent}</w:t></w:r>', $fixed);
$fixed = $templateProcessor->fixBrokenMacros('<w:r><w:t>$1500</w:t><w:t>$</w:t><w:t>{documentContent}</w:t></w:r>');
$this->assertEquals('<w:r><w:t>$1500</w:t><w:t>${documentContent}</w:t></w:r>', $fixed);
$fixed = $templateProcessor->fixBrokenMacros('<w:r><w:t>25$ plus some info {hint}</w:t></w:r>');
$this->assertEquals('<w:r><w:t>25$ plus some info {hint}</w:t></w:r>', $fixed);
$fixed = $templateProcessor->fixBrokenMacros('<w:t>$</w:t></w:r><w:bookmarkStart w:id="0" w:name="_GoBack"/><w:bookmarkEnd w:id="0"/><w:r><w:t xml:space="preserve">15,000.00. </w:t></w:r><w:r w:rsidR="0056499B"><w:t>$</w:t></w:r><w:r w:rsidR="00573DFD" w:rsidRPr="00573DFD"><w:rPr><w:iCs/></w:rPr><w:t>{</w:t></w:r><w:proofErr w:type="spellStart"/><w:r w:rsidR="00573DFD" w:rsidRPr="00573DFD"><w:rPr><w:iCs/></w:rPr><w:t>variable_name</w:t></w:r><w:proofErr w:type="spellEnd"/><w:r w:rsidR="00573DFD" w:rsidRPr="00573DFD"><w:rPr><w:iCs/></w:rPr><w:t>}</w:t></w:r>');
$this->assertEquals('<w:t>$</w:t></w:r><w:bookmarkStart w:id="0" w:name="_GoBack"/><w:bookmarkEnd w:id="0"/><w:r><w:t xml:space="preserve">15,000.00. </w:t></w:r><w:r w:rsidR="0056499B"><w:t>${variable_name}</w:t></w:r>', $fixed);
}
public function testMainPartNameDetection()
{
$templateProcessor = new TemplateProcessor(__DIR__ . '/_files/templates/document22-xml.docx');
$variables = array('test');
$this->assertEquals($variables, $templateProcessor->getVariables());
}
}

View File

@ -73,8 +73,8 @@ class ElementTest extends \PHPUnit\Framework\TestCase
$dom = $this->getAsHTML($phpWord);
$xpath = new \DOMXPath($dom);
$this->assertTrue($xpath->query('/html/body/p[1]/ins')->length == 1);
$this->assertTrue($xpath->query('/html/body/p[2]/del')->length == 1);
$this->assertEquals(1, $xpath->query('/html/body/p[1]/ins')->length);
$this->assertEquals(1, $xpath->query('/html/body/p[2]/del')->length);
}
/**
@ -97,9 +97,9 @@ class ElementTest extends \PHPUnit\Framework\TestCase
$dom = $this->getAsHTML($phpWord);
$xpath = new \DOMXPath($dom);
$this->assertTrue($xpath->query('/html/body/table/tr[1]/td')->length == 1);
$this->assertEquals(1, $xpath->query('/html/body/table/tr[1]/td')->length);
$this->assertEquals('2', $xpath->query('/html/body/table/tr/td[1]')->item(0)->attributes->getNamedItem('colspan')->textContent);
$this->assertTrue($xpath->query('/html/body/table/tr[2]/td')->length == 2);
$this->assertEquals(2, $xpath->query('/html/body/table/tr[2]/td')->length);
}
/**
@ -126,9 +126,9 @@ class ElementTest extends \PHPUnit\Framework\TestCase
$dom = $this->getAsHTML($phpWord);
$xpath = new \DOMXPath($dom);
$this->assertTrue($xpath->query('/html/body/table/tr[1]/td')->length == 2);
$this->assertEquals(2, $xpath->query('/html/body/table/tr[1]/td')->length);
$this->assertEquals('3', $xpath->query('/html/body/table/tr[1]/td[1]')->item(0)->attributes->getNamedItem('rowspan')->textContent);
$this->assertTrue($xpath->query('/html/body/table/tr[2]/td')->length == 1);
$this->assertEquals(1, $xpath->query('/html/body/table/tr[2]/td')->length);
}
private function getAsHTML(PhpWord $phpWord)
@ -155,6 +155,30 @@ class ElementTest extends \PHPUnit\Framework\TestCase
$htmlWriter = new HTML($phpWord);
$content = $htmlWriter->getContent();
$this->assertTrue(strpos($content, $expected) !== false);
$this->assertContains($expected, $content);
}
/**
* Tests writing table with layout
*/
public function testWriteTableLayout()
{
$phpWord = new PhpWord();
$section = $phpWord->addSection();
$section->addTable();
$table1 = $section->addTable(array('layout' => \PhpOffice\PhpWord\Style\Table::LAYOUT_FIXED));
$row1 = $table1->addRow();
$row1->addCell()->addText('fixed layout table');
$table2 = $section->addTable(array('layout' => \PhpOffice\PhpWord\Style\Table::LAYOUT_AUTO));
$row2 = $table2->addRow();
$row2->addCell()->addText('auto layout table');
$dom = $this->getAsHTML($phpWord);
$xpath = new \DOMXPath($dom);
$this->assertEquals('table-layout: fixed;', $xpath->query('/html/body/table[1]')->item(0)->attributes->getNamedItem('style')->textContent);
$this->assertEquals('table-layout: auto;', $xpath->query('/html/body/table[2]')->item(0)->attributes->getNamedItem('style')->textContent);
}
}

View File

@ -492,4 +492,19 @@ class ElementTest extends \PHPUnit\Framework\TestCase
$this->assertTrue($doc->elementExists('/w:document/w:body/w:p[2]/w:pPr/w:pStyle'));
$this->assertEquals('Heading1', $doc->getElementAttribute('/w:document/w:body/w:p[2]/w:pPr/w:pStyle', 'w:val'));
}
/**
* Test correct writing of text with ampersant in it
*/
public function testTextWithAmpersant()
{
\PhpOffice\PhpWord\Settings::setOutputEscapingEnabled(true);
$phpWord = new PhpWord();
$section = $phpWord->addSection();
$section->addText('this text contains an & (ampersant)');
$doc = TestHelperDOCX::getDocument($phpWord);
$this->assertTrue($doc->elementExists('/w:document/w:body/w:p/w:r/w:t'));
$this->assertEquals('this text contains an & (ampersant)', $doc->getElement('/w:document/w:body/w:p/w:r/w:t')->nodeValue);
}
}

View File

@ -51,6 +51,32 @@ class ParagraphTest extends \PHPUnit\Framework\TestCase
$this->assertTrue($doc->elementExists($path));
}
public function testLineSpacingExact()
{
$phpWord = new \PhpOffice\PhpWord\PhpWord();
$section = $phpWord->addSection();
$section->addText('test', null, array('spacing' => 240, 'spacingLineRule' => 'exact'));
$doc = TestHelperDOCX::getDocument($phpWord, 'Word2007');
$path = '/w:document/w:body/w:p/w:pPr/w:spacing';
$this->assertTrue($doc->elementExists($path));
$this->assertEquals('exact', $doc->getElementAttribute($path, 'w:lineRule'));
$this->assertEquals('240', $doc->getElementAttribute($path, 'w:line'));
}
public function testLineSpacingAuto()
{
$phpWord = new \PhpOffice\PhpWord\PhpWord();
$section = $phpWord->addSection();
$section->addText('test', null, array('spacing' => 240, 'spacingLineRule' => 'auto'));
$doc = TestHelperDOCX::getDocument($phpWord, 'Word2007');
$path = '/w:document/w:body/w:p/w:pPr/w:spacing';
$this->assertTrue($doc->elementExists($path));
$this->assertEquals('auto', $doc->getElementAttribute($path, 'w:lineRule'));
$this->assertEquals('480', $doc->getElementAttribute($path, 'w:line'));
}
public function testSuppressAutoHyphens()
{
$paragraphStyle = new ParagraphStyle();

Binary file not shown.

View File

@ -0,0 +1,30 @@
<?php
/**
* This file is part of PHPWord - A pure PHP library for reading and writing
* word processing documents.
*
* PHPWord is free software distributed under the terms of the GNU Lesser
* General Public License version 3 as published by the Free Software Foundation.
*
* For the full copyright and license information, please read the LICENSE
* file that was distributed with this source code. For the full list of
* contributors, visit https://github.com/PHPOffice/PHPWord/contributors.
*
* @see https://github.com/PHPOffice/PHPWord
* @copyright 2010-2018 PHPWord contributors
* @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3
*/
namespace PhpOffice\PhpWord;
class TestableTemplateProcesor extends TemplateProcessor
{
public function __construct()
{
}
public function fixBrokenMacros($documentPart)
{
return parent::fixBrokenMacros($documentPart);
}
}