diff --git a/Classes/PHPWord.php b/Classes/PHPWord.php index d24b9e441b..64f9d9a249 100755 --- a/Classes/PHPWord.php +++ b/Classes/PHPWord.php @@ -39,6 +39,24 @@ class PHPWord { + /** + * Default font name (Arial) + */ + const DEFAULT_FONT_NAME = 'Arial'; + + /** + * Default font size in points (10pt) + * + * 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_SIZE = 10; + + /** + * Default font color (black) + */ + const DEFAULT_FONT_COLOR = '000000'; + /** * Document properties * @@ -74,8 +92,8 @@ class PHPWord public function __construct() { $this->_properties = new PHPWord_DocumentProperties(); - $this->_defaultFontName = 'Arial'; - $this->_defaultFontSize = 20; + $this->_defaultFontName = PHPWord::DEFAULT_FONT_NAME; + $this->_defaultFontSize = PHPWord::DEFAULT_FONT_SIZE; } /** @@ -195,6 +213,16 @@ public function addTitleStyle($titleCount, $styleFont, $styleParagraph = null) PHPWord_Style::addTitleStyle($titleCount, $styleFont, $styleParagraph); } + /** + * Set default paragraph style definition to styles.xml + * + * @param array $styles Paragraph style definition + */ + public function setDefaultParagraphStyle($styles) + { + PHPWord_Style::setDefaultParagraphStyle($styles); + } + /** * Adds a hyperlink style to styles.xml * diff --git a/Classes/PHPWord/Exceptions/InvalidStyleException.php b/Classes/PHPWord/Exceptions/InvalidStyleException.php new file mode 100644 index 0000000000..fb5706252a --- /dev/null +++ b/Classes/PHPWord/Exceptions/InvalidStyleException.php @@ -0,0 +1,15 @@ +_footer; } + + /** + * Create a new Footnote Element + * + * @param string $text + * @return PHPWord_Section_Footnote + */ + public function createFootnote($styleParagraph = null) { + $footnote = new PHPWord_Section_Footnote($styleParagraph); + $refID = PHPWord_Footnote::addFootnoteElement($footnote); + $footnote->setReferenceId($refID); + $this->_elementCollection[] = $footnote; + return $footnote; + } } \ No newline at end of file diff --git a/Classes/PHPWord/Section/Footnote.php b/Classes/PHPWord/Section/Footnote.php new file mode 100644 index 0000000000..7a7d8d6cd3 --- /dev/null +++ b/Classes/PHPWord/Section/Footnote.php @@ -0,0 +1,148 @@ +_elementCollection = array(); + +// Set paragraph style + if(is_array($styleParagraph)) { + $this->_styleParagraph = new PHPWord_Style_Paragraph(); + + foreach($styleParagraph as $key => $value) { + if(substr($key, 0, 1) != '_') { + $key = '_'.$key; + } + $this->_styleParagraph->setStyleValue($key, $value); + } + } else { + $this->_styleParagraph = $styleParagraph; + } + } + + + /** + * Add a Text Element + * + * @var string $text + * @var mixed $styleFont + * @return PHPWord_Section_Text + */ + public function addText($text = null, $styleFont = null) { + $givenText = $text; + $text = new PHPWord_Section_Text($givenText, $styleFont); + $this->_elementCollection[] = $text; + return $text; + } + + /** + * Add a Link Element + * + * @param string $linkSrc + * @param string $linkName + * @param mixed $styleFont + * @return PHPWord_Section_Link + */ + public function addLink($linkSrc, $linkName = null, $styleFont = null) { + + $link = new PHPWord_Section_Link($linkSrc, $linkName, $styleFont); + $rID = PHPWord_Footnote::addFootnoteLinkElement($linkSrc); + $link->setRelationId($rID); + + $this->_elementCollection[] = $link; + return $link; + } + + /** + * Get Footnote content + * + * @return string + */ + public function getElements() { + return $this->_elementCollection; + } + + /** + * Get Paragraph style + * + * @return PHPWord_Style_Paragraph + */ + public function getParagraphStyle() { + return $this->_styleParagraph; + } + + /** + * Get Footnote Reference ID + * + * @return int + */ + public function getReferenceId() { + return $this->_refId; + } + + /** + * Set Footnote Reference ID + * + * @param int $refId + */ + public function setReferenceId($refId) { + $this->_refId = $refId; + } +} \ No newline at end of file diff --git a/Classes/PHPWord/Section/Settings.php b/Classes/PHPWord/Section/Settings.php index 020a82e374..ba59525925 100755 --- a/Classes/PHPWord/Section/Settings.php +++ b/Classes/PHPWord/Section/Settings.php @@ -158,6 +158,44 @@ class PHPWord_Section_Settings */ private $pageNumberingStart; + /** + * @var int + */ + private $headerHeight; + + /** + * @var int + */ + private $footerHeight; + + /** + * Section columns count + * + * @var int + */ + private $_colsNum; + + /** + * Section spacing between columns + * + * @var int + */ + private $_colsSpace; + + /** + * Section break type + * + * Options: + * - nextPage: Next page section break + * - nextColumn: Column section break + * - continuous: Continuous section break + * - evenPage: Even page section break + * - oddPage: Odd page section break + * + * @var string + */ + private $_breakType; + /** * Create new Section Settings */ @@ -178,6 +216,11 @@ public function __construct() $this->_borderRightColor = null; $this->_borderBottomSize = null; $this->_borderBottomColor = null; + $this->headerHeight = 720; // set default header and footer to 720 twips (.5 inches) + $this->footerHeight = 720; + $this->_colsNum = 1; + $this->_colsSpace = 720; + $this->_breakType = null; } /** @@ -568,4 +611,100 @@ public function getPageNumberingStart() { return $this->pageNumberingStart; } + + /** + * Get Header Height + * + * @return int + */ + public function getHeaderHeight() { + return $this->headerHeight; + } + + /** + * Set Header Height + * + * @param int $pValue + */ + public function setHeaderHeight($pValue = '') { + $this->headerHeight = $pValue; + return $this; + } + + /** + * Get Footer Height + * + * @return int + */ + public function getFooterHeight() { + return $this->footerHeight; + } + + /** + * Set Footer Height + * + * @param int $pValue + */ + public function setFooterHeight($pValue = '') { + $this->footerHeight = $pValue; + return $this; + } + + /** + * Set Section Columns Count + * + * @param in $pValue + */ + public function setColsNum($pValue = '') { + $this->_colsNum = $pValue; + return $this; + } + + /** + * Get Section Columns Count + * + * @return int + */ + public function getColsNum() { + return $this->_colsNum; + } + + /** + * Set Section Space Between Columns + * + * @param int $pValue + */ + public function setColsSpace($pValue = '') { + $this->_colsSpace = $pValue; + return $this; + } + + /** + * Get Section Space Between Columns + * + * @return int + */ + public function getColsSpace() { + return $this->_colsSpace; + } + + /** + * Set Break Type + * + * @param string $pValue + */ + public function setBreakType($pValue = null) { + $this->_breakType = $pValue; + return $this; + } + + /** + * Get Break Type + * + * @return string + */ + public function getBreakType() { + return $this->_breakType; + } + } diff --git a/Classes/PHPWord/Section/Table.php b/Classes/PHPWord/Section/Table.php index 6d68351a9a..081b648423 100755 --- a/Classes/PHPWord/Section/Table.php +++ b/Classes/PHPWord/Section/Table.php @@ -45,13 +45,6 @@ class PHPWord_Section_Table */ private $_rows = array(); - /** - * Row heights - * - * @var array - */ - private $_rowHeights = array(); - /** * Table holder * @@ -66,6 +59,13 @@ class PHPWord_Section_Table */ private $_pCount; + /** + * Table width + * + * @var int + */ + private $_width = null; + /** * Create a new table @@ -100,10 +100,11 @@ public function __construct($insideOf, $pCount, $style = null) * * @param int $height */ - public function addRow($height = null) + public function addRow($height = null, $style = null) { - $this->_rows[] = array(); - $this->_rowHeights[] = $height; + $row = new PHPWord_Section_Table_Row($this->_insideOf, $this->_pCount, $height, $style); + $this->_rows[] = $row; + return $row; } /** @@ -113,11 +114,10 @@ public function addRow($height = null) * @param mixed $style * @return PHPWord_Section_Table_Cell */ - public function addCell($width, $style = null) + public function addCell($width = null, $style = null) { - $cell = new PHPWord_Section_Table_Cell($this->_insideOf, $this->_pCount, $width, $style); $i = count($this->_rows) - 1; - $this->_rows[$i][] = $cell; + $cell = $this->_rows[$i]->addCell($width, $style); return $cell; } @@ -132,22 +132,33 @@ public function getRows() } /** - * Get all row heights + * Get table style * - * @return array + * @return PHPWord_Style_Table */ - public function getRowHeights() + public function getStyle() { - return $this->_rowHeights; + return $this->_style; } /** - * Get table style + * Set table width * - * @return PHPWord_Style_Table + * @var int $width */ - public function getStyle() + public function setWidth($width) { - return $this->_style; + $this->_width = $width; + } + + /** + * Get table width + * + * @return int + */ + public function getWidth() + { + return $this->_width; } + } diff --git a/Classes/PHPWord/Section/Table/Row.php b/Classes/PHPWord/Section/Table/Row.php new file mode 100644 index 0000000000..c2db614b2f --- /dev/null +++ b/Classes/PHPWord/Section/Table/Row.php @@ -0,0 +1,141 @@ +_insideOf = $insideOf; + $this->_pCount = $pCount; + $this->_height = $height; + $this->_style = new PHPWord_Style_Row(); + + if (!is_null($style)) { + if (is_array($style)) { + + foreach ($style as $key => $value) { + if (substr($key, 0, 1) != '_') { + $key = '_' . $key; + } + $this->_style->setStyleValue($key, $value); + } + } + } + } + + /** + * Add a cell + * + * @param int $width + * @param mixed $style + * @return PHPWord_Section_Table_Cell + */ + public function addCell($width = null, $style = null) + { + $cell = new PHPWord_Section_Table_Cell($this->_insideOf, $this->_pCount, $width, $style); + $this->_cells[] = $cell; + return $cell; + } + + /** + * Get all cells + * + * @return array + */ + public function getCells() + { + return $this->_cells; + } + + /** + * Get row style + * + * @return PHPWord_Style_Row + */ + public function getStyle() + { + return $this->_style; + } + + /** + * Get row height + * + * @return int + */ + public function getHeight() + { + return $this->_height; + } +} \ No newline at end of file diff --git a/Classes/PHPWord/Section/Text.php b/Classes/PHPWord/Section/Text.php index 2b37e7d401..a4e95c9fbd 100755 --- a/Classes/PHPWord/Section/Text.php +++ b/Classes/PHPWord/Section/Text.php @@ -48,7 +48,7 @@ class PHPWord_Section_Text /** * Paragraph style * - * @var PHPWord_Style_Font + * @var \PHPWord_Style_Paragraph */ private $_styleParagraph; @@ -116,7 +116,9 @@ public function getParagraphStyle() /** * Set Paragraph style * - * @return PHPWord_Style_Paragraph + * @param array|\PHPWord_Style_Paragraph $styleParagraph + * @return \PHPWord_Style_Paragraph + * @throws \Exception */ public function setParagraphStyle($styleParagraph) { @@ -124,14 +126,19 @@ public function setParagraphStyle($styleParagraph) $this->_styleParagraph = new PHPWord_Style_Paragraph(); foreach ($styleParagraph as $key => $value) { - if (substr($key, 0, 1) != '_') { + if ($key === 'line-height') { + null; + } elseif (substr($key, 0, 1) != '_') { $key = '_' . $key; } $this->_styleParagraph->setStyleValue($key, $value); } - } else { + } elseif ($styleParagraph instanceof PHPWord_Style_Paragraph) { $this->_styleParagraph = $styleParagraph; + } else { + throw new Exception('Expected array or PHPWord_Style_Paragraph'); } + return $this->_styleParagraph; } /** @@ -143,4 +150,4 @@ public function getText() { return $this->_text; } -} +} \ No newline at end of file diff --git a/Classes/PHPWord/Section/TextRun.php b/Classes/PHPWord/Section/TextRun.php index a9104341d3..7c03138bcb 100755 --- a/Classes/PHPWord/Section/TextRun.php +++ b/Classes/PHPWord/Section/TextRun.php @@ -109,6 +109,41 @@ public function addLink($linkSrc, $linkName = null, $styleFont = null) return $link; } + /** + * Add a Image Element + * + * @param string $imageSrc + * @param mixed $styleFont + * @return PHPWord_Section_Image + */ + public function addImage($imageSrc, $style = null) { + $image = new PHPWord_Section_Image($imageSrc, $style); + + if (!is_null($image->getSource())) { + $rID = PHPWord_Media::addSectionMediaElement($imageSrc, 'image'); + $image->setRelationId($rID); + + $this->_elementCollection[] = $image; + return $image; + } else { + trigger_error('Source does not exist or unsupported image type.'); + } + } + + /** + * Create a new Footnote Element + * + * @param string $text + * @return PHPWord_Section_Footnote + */ + public function createFootnote($styleParagraph = null) { + $footnote = new PHPWord_Section_Footnote($styleParagraph); + $refID = PHPWord_Footnote::addFootnoteElement($footnote); + $footnote->setReferenceId($refID); + $this->_elementCollection[] = $footnote; + return $footnote; + } + /** * Get TextRun content * diff --git a/Classes/PHPWord/Shared/Drawing.php b/Classes/PHPWord/Shared/Drawing.php index dba204e3bc..064e6fcc6d 100755 --- a/Classes/PHPWord/Shared/Drawing.php +++ b/Classes/PHPWord/Shared/Drawing.php @@ -128,7 +128,7 @@ public static function pixelsToCentimeters($pValue = 0) public static function centimetersToPixels($pValue = 0) { if ($pValue != 0) { - return $pValue * 0.028; + return $pValue / 0.028; } else { return 0; } diff --git a/Classes/PHPWord/Shared/Font.php b/Classes/PHPWord/Shared/Font.php index be3cf1a8b6..ccb19bc743 100755 --- a/Classes/PHPWord/Shared/Font.php +++ b/Classes/PHPWord/Shared/Font.php @@ -77,4 +77,16 @@ public static function pixelSizeToTwips($sizeInPixel = 1) { return self::centimeterSizeToTwips($sizeInPixel / 37.795275591); } + + /** + * Calculate twip based on point size, used mainly for paragraph spacing + * + * @param int|float $sizeInPoint Size in point + * @return int|float Size (in twips) + */ + public static function pointSizeToTwips($sizeInPoint = 1) + { + return ($sizeInPoint * 20); + } + } diff --git a/Classes/PHPWord/Style.php b/Classes/PHPWord/Style.php index 7b20f8ab07..daabd46bb7 100755 --- a/Classes/PHPWord/Style.php +++ b/Classes/PHPWord/Style.php @@ -140,6 +140,16 @@ public static function addTitleStyle($titleCount, $styleFont, $styleParagraph = } } + /** + * Set default paragraph style + * + * @param array $styles Paragraph style definition + */ + public static function setDefaultParagraphStyle($styles) + { + self::addParagraphStyle('Normal', $styles); + } + /** * Get all styles * diff --git a/Classes/PHPWord/Style/Cell.php b/Classes/PHPWord/Style/Cell.php index e7d2bf9125..1e534e2391 100755 --- a/Classes/PHPWord/Style/Cell.php +++ b/Classes/PHPWord/Style/Cell.php @@ -198,11 +198,6 @@ public function setBgColor($pValue = null) $this->_bgColor = $pValue; } - public function setHeight($pValue = null) - { - $this->_height = $pValue; - } - public function setBorderSize($pValue = null) { $this->_borderTopSize = $pValue; diff --git a/Classes/PHPWord/Style/Font.php b/Classes/PHPWord/Style/Font.php index e273dd35da..43495cdc2f 100755 --- a/Classes/PHPWord/Style/Font.php +++ b/Classes/PHPWord/Style/Font.php @@ -80,29 +80,94 @@ class PHPWord_Style_Font */ private $_paragraphStyle; - private $_size; + /** + * Font name + * + * @var int|float + */ private $_name; + + /** + * Font size + * + * @var int|float + */ + private $_size; + + /** + * Bold + * + * @var bool + */ private $_bold; + + /** + * Italics + * + * @var bool + */ private $_italic; + + /** + * Superscript + * + * @var bool + */ private $_superScript; + + /** + * Subscript + * + * @var bool + */ private $_subScript; + + /** + * Underline mode + * + * @var string + */ private $_underline; + + /** + * Strikethrough + * + * @var bool + */ private $_strikethrough; + + /** + * Font color + * + * @var string + */ private $_color; + + /** + * Foreground/highlight + * + * @var string + */ private $_fgColor; + /** + * New font style + * + * @param string $type Type of font + * @param array $styleParagraph Paragraph styles definition + */ public function __construct($type = 'text', $styleParagraph = null) { $this->_type = $type; - $this->_name = 'Arial'; - $this->_size = 20; + $this->_name = PHPWord::DEFAULT_FONT_NAME; + $this->_size = PHPWord::DEFAULT_FONT_SIZE; $this->_bold = false; $this->_italic = false; $this->_superScript = false; $this->_subScript = false; $this->_underline = PHPWord_Style_Font::UNDERLINE_NONE; $this->_strikethrough = false; - $this->_color = '000000'; + $this->_color = PHPWord::DEFAULT_FONT_COLOR; $this->_fgColor = null; if (!is_null($styleParagraph)) { @@ -119,78 +184,139 @@ public function __construct($type = 'text', $styleParagraph = null) } } - public function getName() + /** + * Set style value + * + * @param string $key + * @param mixed $value + */ + public function setStyleValue($key, $value) { - return $this->_name; + $method = 'set' . substr($key, 1); + if (method_exists($this, $method)) { + $this->$method($value); + } } - public function setStyleValue($key, $value) + /** + * Get font name + * + * @return bool + */ + public function getName() { - if ($key == '_size') { - $value *= 2; - } - $this->$key = $value; + return $this->_name; } - public function setName($pValue = 'Arial') + /** + * Set font name + * + * @param string $pValue + * @return PHPWord_Style_Font + */ + public function setName($pValue = PHPWord::DEFAULT_FONT_NAME) { - if ($pValue == '') { - $pValue = 'Arial'; + if (is_null($pValue) || $pValue == '') { + $pValue = PHPWord::DEFAULT_FONT_NAME; } $this->_name = $pValue; return $this; } + /** + * Get font size + * + * @return int|float + */ public function getSize() { return $this->_size; } - public function setSize($pValue = 20) + /** + * Set font size + * + * @param int|float $pValue + * @return PHPWord_Style_Font + */ + public function setSize($pValue = PHPWord::DEFAULT_FONT_SIZE) { - if ($pValue == '') { - $pValue = 20; + if (!is_numeric($pValue)) { + $pValue = PHPWord::DEFAULT_FONT_SIZE; } - $this->_size = ($pValue * 2); + $this->_size = $pValue; return $this; } + /** + * Get bold + * + * @return bool + */ public function getBold() { return $this->_bold; } + /** + * Set bold + * + * @param bool $pValue + * @return PHPWord_Style_Font + */ public function setBold($pValue = false) { - if ($pValue == '') { + if (!is_bool($pValue)) { $pValue = false; } $this->_bold = $pValue; return $this; } + /** + * Get italics + * + * @return bool + */ public function getItalic() { return $this->_italic; } + /** + * Set italics + * + * @param bool $pValue + * @return PHPWord_Style_Font + */ public function setItalic($pValue = false) { - if ($pValue == '') { + if (!is_bool($pValue)) { $pValue = false; } $this->_italic = $pValue; return $this; } + /** + * Get superscript + * + * @return bool + */ public function getSuperScript() { return $this->_superScript; } + /** + * Set superscript + * + * @param bool $pValue + * @return PHPWord_Style_Font + */ public function setSuperScript($pValue = false) { - if ($pValue == '') { + if (!is_bool($pValue)) { $pValue = false; } $this->_superScript = $pValue; @@ -198,14 +324,25 @@ public function setSuperScript($pValue = false) return $this; } + /** + * Get superscript + * + * @return bool + */ public function getSubScript() { return $this->_subScript; } + /** + * Set subscript + * + * @param bool $pValue + * @return PHPWord_Style_Font + */ public function setSubScript($pValue = false) { - if ($pValue == '') { + if (!is_bool($pValue)) { $pValue = false; } $this->_subScript = $pValue; @@ -213,11 +350,22 @@ public function setSubScript($pValue = false) return $this; } + /** + * Get underline + * + * @return string + */ public function getUnderline() { return $this->_underline; } + /** + * Set underline + * + * @param string $pValue + * @return PHPWord_Style_Font + */ public function setUnderline($pValue = PHPWord_Style_Font::UNDERLINE_NONE) { if ($pValue == '') { @@ -227,49 +375,90 @@ public function setUnderline($pValue = PHPWord_Style_Font::UNDERLINE_NONE) return $this; } + /** + * Get strikethrough + * + * @return bool + */ public function getStrikethrough() { return $this->_strikethrough; } + /** + * Set strikethrough + * + * @param bool $pValue + * @return PHPWord_Style_Font + */ public function setStrikethrough($pValue = false) { - if ($pValue == '') { + if (!is_bool($pValue)) { $pValue = false; } $this->_strikethrough = $pValue; return $this; } + /** + * Get font color + * + * @return string + */ public function getColor() { return $this->_color; } - public function setColor($pValue = '000000') + /** + * Set font color + * + * @param string $pValue + * @return PHPWord_Style_Font + */ + public function setColor($pValue = PHPWord::DEFAULT_FONT_COLOR) { + if (is_null($pValue) || $pValue == '') { + $pValue = PHPWord::DEFAULT_FONT_COLOR; + } $this->_color = $pValue; return $this; } + /** + * Get foreground/highlight color + * + * @return bool + */ public function getFgColor() { return $this->_fgColor; } + /** + * Set foreground/highlight color + * + * @param string $pValue + * @return PHPWord_Style_Font + */ public function setFgColor($pValue = null) { $this->_fgColor = $pValue; return $this; } + /** + * Get style type + * + * @return string + */ public function getStyleType() { return $this->_type; } /** - * Get Paragraph style + * Get paragraph style * * @return PHPWord_Style_Paragraph */ diff --git a/Classes/PHPWord/Style/Paragraph.php b/Classes/PHPWord/Style/Paragraph.php index ab285ebea3..d49e6d1ec7 100755 --- a/Classes/PHPWord/Style/Paragraph.php +++ b/Classes/PHPWord/Style/Paragraph.php @@ -25,11 +25,21 @@ * @version 0.7.0 */ +use PHPWord\Exceptions\InvalidStyleException; + /** * PHPWord_Style_Paragraph */ class PHPWord_Style_Paragraph { + const LINE_HEIGHT = 240; + + /* + * Text line height + * + * @var int + */ + private $lineHeight; /** * Paragraph alignment @@ -73,20 +83,6 @@ class PHPWord_Style_Paragraph */ private $_indent; - - /** - * New Paragraph Style - */ - public function __construct() - { - $this->_align = null; - $this->_spaceBefore = null; - $this->_spaceAfter = null; - $this->_spacing = null; - $this->_tabs = null; - $this->_indent = null; - } - /** * Set Style value * @@ -97,14 +93,18 @@ public function setStyleValue($key, $value) { if ($key == '_indent') { $value = (int)$value * 720; // 720 twips per indent - } - if ($key == '_spacing') { + $this->$key = $value; + } elseif ($key == '_spacing') { $value += 240; // because line height of 1 matches 240 twips - } - if ($key === '_tabs') { + $this->$key = $value; + } elseif ($key === '_tabs') { $value = new PHPWord_Style_Tabs($value); + $this->$key = $value; + } elseif ($key === 'line-height') { + $this->setLineHeight($value); + } else { + $this->$key = $value; } - $this->$key = $value; } /** @@ -230,4 +230,34 @@ public function getTabs() { return $this->_tabs; } + + /** + * Set the line height + * + * @param int|float|string $lineHeight + * @return $this + * @throws \PHPWord\Exceptions\InvalidStyleException + */ + public function setLineHeight($lineHeight) + { + if (is_string($lineHeight)) { + $lineHeight = floatval(preg_replace('/[^0-9\.\,]/', '', $lineHeight)); + } + + if ((!is_integer($lineHeight) && !is_float($lineHeight)) || !$lineHeight) { + throw new InvalidStyleException('Line height must be a valid number'); + } + + $this->lineHeight = $lineHeight; + $this->setSpacing($lineHeight * self::LINE_HEIGHT); + return $this; + } + + /** + * @return int + */ + public function getLineHeight() + { + return $this->lineHeight; + } } \ No newline at end of file diff --git a/Classes/PHPWord/Style/Row.php b/Classes/PHPWord/Style/Row.php new file mode 100644 index 0000000000..a0e79b3a5e --- /dev/null +++ b/Classes/PHPWord/Style/Row.php @@ -0,0 +1,85 @@ +_tblHeader = null; + $this->_cantSplit = null; + } + + /** + * Set style value + */ + public function setStyleValue($key, $value) + { + $this->$key = $value; + } + + public function setTblHeader($pValue = null) + { + $this->_tblHeader = $pValue; + } + + public function getTblHeader() + { + return $this->_tblHeader ? 1 : 0; + } + + public function setCantSplit($pValue = null) + { + $this->_cantSplit = $pValue; + } + + public function getCantSplit() + { + return $this->_cantSplit ? 1 : 0; + } + +} \ No newline at end of file diff --git a/Classes/PHPWord/Template.php b/Classes/PHPWord/Template.php index 83a45949c1..edf0de754b 100755 --- a/Classes/PHPWord/Template.php +++ b/Classes/PHPWord/Template.php @@ -64,7 +64,7 @@ public function __construct($strFilename) if ($this->_tempFileName !== false) { // Copy the source File to the temp File if (!copy($strFilename, $this->_tempFileName)) { - throw new PHPWord_Exception('Could not copy the template from ' . $strFilename . ' to ' . $this->_tempFileName . '.'); + throw new PHPWord_Exception("Could not copy the template from {$strFilename} to {$this->_tempFileName}."); } $this->_objZip = new ZipArchive(); @@ -75,14 +75,45 @@ public function __construct($strFilename) throw new PHPWord_Exception('Could not create temporary file with unique name in the default temporary directory.'); } } + + /** + * Applies XSL style sheet to template's parts + * + * @param DOMDocument &$xslDOMDocument + * @param array $xslOptions = array() + * @param string $xslOptionsURI = '' + */ + public function applyXslStyleSheet(&$xslDOMDocument, $xslOptions = array(), $xslOptionsURI = '') + { + $processor = new \XSLTProcessor(); + + $processor->importStylesheet($xslDOMDocument); + + if ($processor->setParameter($xslOptionsURI, $xslOptions) === false) { + throw new \Exception('Could not set values for the given XSL style sheet parameters.'); + } + + $xmlDOMDocument = new \DOMDocument(); + if ($xmlDOMDocument->loadXML($this->_documentXML) === false) { + throw new \Exception('Could not load XML from the given template.'); + } + + $xmlTransformed = $processor->transformToXml($xmlDOMDocument); + if ($xmlTransformed === false) { + throw new \Exception('Could not transform the given XML document.'); + } + + $this->_documentXML = $xmlTransformed; + } /** * Set a Template value * * @param mixed $search * @param mixed $replace + * @param integer $limit */ - public function setValue($search, $replace) + public function setValue($search, $replace, $limit = -1) { $pattern = '|\$\{([^\}]+)\}|U'; preg_match_all($pattern, $this->_documentXML, $matches); @@ -100,9 +131,16 @@ public function setValue($search, $replace) if (!PHPWord_Shared_String::IsUTF8($replace)) { $replace = utf8_encode($replace); } - } + $replace = htmlspecialchars($replace); + } else { + foreach($replace as $key=>$value) { + $replace[$key] = htmlspecialchars($value); + } + } - $this->_documentXML = str_replace($search, $replace, $this->_documentXML); + $regExpDelim = '/'; + $escapedSearch = preg_quote($search, $regExpDelim); + $this->_documentXML = preg_replace("{$regExpDelim}{$escapedSearch}{$regExpDelim}u", $replace, $this->_documentXML, $limit); } /** @@ -114,6 +152,99 @@ public function getVariables() return $matches[1]; } + /** + * Find the start position of the nearest table row before $offset + * + * @param mixed $offset + */ + private function _findRowStart($offset) { + $rowStart = strrpos($this->_documentXML, "_documentXML) - $offset) * -1)); + if (!$rowStart) { + $rowStart = strrpos($this->_documentXML, "", ((strlen($this->_documentXML) - $offset) * -1)); + } + if (!$rowStart) { + trigger_error("Can not find the start position of the row to clone."); + return false; + } + return $rowStart; + } + + /** + * Find the end position of the nearest table row after $offset + * + * @param mixed $offset + */ + private function _findRowEnd($offset) { + $rowEnd = strpos($this->_documentXML, "", $offset) + 7; + return $rowEnd; + } + + /** + * Get a slice of a string + * + * @param mixed $offset + */ + private function _getSlice($startPosition, $endPosition = 0) { + if (!$endPosition) { + $endPosition = strlen($this->_documentXML); + } + return substr($this->_documentXML, $startPosition, ($endPosition - $startPosition)); + } + + /** + * Clone a table row in a template document + * + * @param mixed $search + * @param mixed $numberOfClones + */ + public function cloneRow($search, $numberOfClones) { + if(substr($search, 0, 2) !== '${' && substr($search, -1) !== '}') { + $search = '${'.$search.'}'; + } + + $tagPos = strpos($this->_documentXML, $search); + if (!$tagPos) { + trigger_error("Can not clone row, template variable not found or variable contains markup."); + return false; + } + + $rowStart = $this->_findRowStart($tagPos); + $rowEnd = $this->_findRowEnd($tagPos); + $xmlRow = $this->_getSlice($rowStart, $rowEnd); + + // Check if there's a cell spanning multiple rows. + if (preg_match('##', $xmlRow)) { + $extraRowStart = $rowEnd; + $extraRowEnd = $rowEnd; + while(true) { + $extraRowStart = $this->_findRowStart($extraRowEnd + 1); + $extraRowEnd = $this->_findRowEnd($extraRowEnd + 1); + + // If extraRowEnd is lower then 7, there was no next row found. + if ($extraRowEnd < 7) { + break; + } + + // If tmpXmlRow doesn't contain continue, this row is no longer part of the spanned row. + $tmpXmlRow = $this->_getSlice($extraRowStart, $extraRowEnd); + if (!preg_match('##', $tmpXmlRow) && !preg_match('##', $tmpXmlRow)) { + break; + } + // This row was a spanned row, update $rowEnd and search for the next row. + $rowEnd = $extraRowEnd; + } + $xmlRow = $this->_getSlice($rowStart, $rowEnd); + } + + $result = $this->_getSlice(0, $rowStart); + for ($i = 1; $i <= $numberOfClones; $i++) { + $result .= preg_replace('/\$\{(.*?)\}/','\${\\1#'.$i.'}', $xmlRow); + } + $result .= $this->_getSlice($rowEnd); + + $this->_documentXML = $result; + } + /** * Save Template * diff --git a/Classes/PHPWord/Writer/ODText/Content.php b/Classes/PHPWord/Writer/ODText/Content.php index d2690aff9c..fad07d5a63 100755 --- a/Classes/PHPWord/Writer/ODText/Content.php +++ b/Classes/PHPWord/Writer/ODText/Content.php @@ -115,7 +115,7 @@ public function writeContent(PHPWord $pPHPWord = null) $numPStyles++; $pPHPWord->addParagraphStyle('P' . $numPStyles, array()); - $element->setParagraph('P' . $numPStyles); + $element->setParagraphStyle('P' . $numPStyles); } } } @@ -145,10 +145,10 @@ public function writeContent(PHPWord $pPHPWord = null) } } } - if (!in_array('Arial', $arrFonts)) { + if (!in_array(PHPWord::DEFAULT_FONT_NAME, $arrFonts)) { $objWriter->startElement('style:font-face'); - $objWriter->writeAttribute('style:name', 'Arial'); - $objWriter->writeAttribute('svg:font-family', 'Arial'); + $objWriter->writeAttribute('style:name', PHPWord::DEFAULT_FONT_NAME); + $objWriter->writeAttribute('svg:font-family', PHPWord::DEFAULT_FONT_NAME); $objWriter->endElement(); } } @@ -338,4 +338,15 @@ protected function _writeTextBreak(PHPWord_Shared_XMLWriter $objWriter = null) private function _writeEndSection(PHPWord_Shared_XMLWriter $objWriter = null, PHPWord_Section $section) { } + + /** + * Dummy function just to make all samples produce ODT + * + * @todo Create the real function + */ + private function _writeSection( + PHPWord_Shared_XMLWriter $objWriter = null, + PHPWord_Section $section) + { + } } diff --git a/Classes/PHPWord/Writer/ODText/Styles.php b/Classes/PHPWord/Writer/ODText/Styles.php index 3c485e551b..745da08ee2 100755 --- a/Classes/PHPWord/Writer/ODText/Styles.php +++ b/Classes/PHPWord/Writer/ODText/Styles.php @@ -104,10 +104,10 @@ public function writeStyles(PHPWord $pPHPWord = null) } } } - if (!in_array('Arial', $arrFonts)) { + if (!in_array(PHPWord::DEFAULT_FONT_NAME, $arrFonts)) { $objWriter->startElement('style:font-face'); - $objWriter->writeAttribute('style:name', 'Arial'); - $objWriter->writeAttribute('svg:font-family', 'Arial'); + $objWriter->writeAttribute('style:name', PHPWord::DEFAULT_FONT_NAME); + $objWriter->writeAttribute('svg:font-family', PHPWord::DEFAULT_FONT_NAME); $objWriter->endElement(); } $objWriter->endElement(); @@ -132,17 +132,17 @@ public function writeStyles(PHPWord $pPHPWord = null) // style:text-properties $objWriter->startElement('style:text-properties'); $objWriter->writeAttribute('style:use-window-font-color', 'true'); - $objWriter->writeAttribute('style:font-name', 'Arial'); - $objWriter->writeAttribute('fo:font-size', '10pt'); + $objWriter->writeAttribute('style:font-name', PHPWord::DEFAULT_FONT_NAME); + $objWriter->writeAttribute('fo:font-size', PHPWord::DEFAULT_FONT_SIZE . 'pt'); $objWriter->writeAttribute('fo:language', 'fr'); $objWriter->writeAttribute('fo:country', 'FR'); $objWriter->writeAttribute('style:letter-kerning', 'true'); - $objWriter->writeAttribute('style:font-name-asian', 'Arial2'); - $objWriter->writeAttribute('style:font-size-asian', '10pt'); + $objWriter->writeAttribute('style:font-name-asian', PHPWord::DEFAULT_FONT_NAME . '2'); + $objWriter->writeAttribute('style:font-size-asian', PHPWord::DEFAULT_FONT_SIZE . 'pt'); $objWriter->writeAttribute('style:language-asian', 'zh'); $objWriter->writeAttribute('style:country-asian', 'CN'); - $objWriter->writeAttribute('style:font-name-complex', 'Arial2'); - $objWriter->writeAttribute('style:font-size-complex', '10pt'); + $objWriter->writeAttribute('style:font-name-complex', PHPWord::DEFAULT_FONT_NAME . '2'); + $objWriter->writeAttribute('style:font-size-complex', PHPWord::DEFAULT_FONT_SIZE . 'pt'); $objWriter->writeAttribute('style:language-complex', 'hi'); $objWriter->writeAttribute('style:country-complex', 'IN'); $objWriter->writeAttribute('fo:hyphenate', 'false'); @@ -168,9 +168,9 @@ public function writeStyles(PHPWord $pPHPWord = null) // style:text-properties $objWriter->startElement('style:text-properties'); - $objWriter->writeAttribute('fo:font-size', ($style->getSize() / 2) . 'pt'); - $objWriter->writeAttribute('style:font-size-asian', ($style->getSize() / 2) . 'pt'); - $objWriter->writeAttribute('style:font-size-complex', ($style->getSize() / 2) . 'pt'); + $objWriter->writeAttribute('fo:font-size', ($style->getSize()) . 'pt'); + $objWriter->writeAttribute('style:font-size-asian', ($style->getSize()) . 'pt'); + $objWriter->writeAttribute('style:font-size-complex', ($style->getSize()) . 'pt'); if ($style->getItalic()) { $objWriter->writeAttribute('fo:font-style', 'italic'); $objWriter->writeAttribute('style:font-style-asian', 'italic'); diff --git a/Classes/PHPWord/Writer/RTF.php b/Classes/PHPWord/Writer/RTF.php index ebaa00dad8..1240090769 100755 --- a/Classes/PHPWord/Writer/RTF.php +++ b/Classes/PHPWord/Writer/RTF.php @@ -176,7 +176,7 @@ private function _getData() // Point size (in half-points) above which to kern character pairs $sRTFContent .= '\kerning1'; // Set the font size in half-points - $sRTFContent .= '\fs20'; + $sRTFContent .= '\fs' . (PHPWord::DEFAULT_FONT_SIZE * 2); // Body $sRTFContent .= $this->_getDataContent(); @@ -191,8 +191,8 @@ private function _getDataFont() $pPHPWord = $this->_document; $arrFonts = array(); - // Default font : Arial - $arrFonts[] = 'Arial'; + // Default font : PHPWord::DEFAULT_FONT_NAME + $arrFonts[] = PHPWord::DEFAULT_FONT_NAME; // PHPWord object : $this->_document // Browse styles @@ -252,10 +252,10 @@ private function _getDataColor() if ($style instanceof PHPWord_Style_Font) { $color = $style->getColor(); $fgcolor = $style->getFgColor(); - if (in_array($color, $arrColors) == FALSE && $color != '000000' && !empty($color)) { + if (in_array($color, $arrColors) == FALSE && $color != PHPWord::DEFAULT_FONT_COLOR && !empty($color)) { $arrColors[] = $color; } - if (in_array($fgcolor, $arrColors) == FALSE && $fgcolor != '000000' && !empty($fgcolor)) { + if (in_array($fgcolor, $arrColors) == FALSE && $fgcolor != PHPWord::DEFAULT_FONT_COLOR && !empty($fgcolor)) { $arrColors[] = $fgcolor; } } @@ -400,7 +400,7 @@ private function _getDataContent_writeText(PHPWord_Section_Text $text) $sRTFText .= '\i'; } if ($styleFont->getSize()) { - $sRTFText .= '\fs' . $styleFont->getSize(); + $sRTFText .= '\fs' . ($styleFont->getSize() * 2); } } if ($this->_lastParagraphStyle != '' || $styleFont) { @@ -419,7 +419,7 @@ private function _getDataContent_writeText(PHPWord_Section_Text $text) $sRTFText .= '\i0'; } if ($styleFont->getSize()) { - $sRTFText .= '\fs20'; + $sRTFText .= '\fs' . (PHPWord::DEFAULT_FONT_SIZE * 2); } } diff --git a/Classes/PHPWord/Writer/Word2007.php b/Classes/PHPWord/Writer/Word2007.php index 6dfc95d343..b55fb55677 100755 --- a/Classes/PHPWord/Writer/Word2007.php +++ b/Classes/PHPWord/Writer/Word2007.php @@ -52,6 +52,8 @@ public function __construct(PHPWord $PHPWord = null) $this->_writerParts['styles'] = new PHPWord_Writer_Word2007_Styles(); $this->_writerParts['header'] = new PHPWord_Writer_Word2007_Header(); $this->_writerParts['footer'] = new PHPWord_Writer_Word2007_Footer(); + $this->_writerParts['footnotes'] = new PHPWord_Writer_Word2007_Footnotes(); + $this->_writerParts['footnotesrels'] = new PHPWord_Writer_Word2007_FootnotesRels(); foreach ($this->_writerParts as $writer) { $writer->setParentWriter($this); @@ -111,6 +113,11 @@ public function save($pFilename = null) } } + $footnoteLinks = array(); + $_footnoteElements = PHPWord_Footnote::getFootnoteLinkElements(); + foreach($_footnoteElements as $element) { // loop through footnote link elements + $footnoteLinks[] = $element; + } $_cHdrs = 0; $_cFtrs = 0; @@ -138,6 +145,16 @@ public function save($pFilename = null) } } + if (PHPWord_Footnote::countFootnoteElements() > 0) { + $_allFootnotesCollection = PHPWord_Footnote::getFootnoteElements(); + $_footnoteFile = 'footnotes.xml'; + $sectionElements[] = array('target'=>$_footnoteFile, 'type'=>'footnotes', 'rID'=>++$rID); + $objZip->addFromString('word/'.$_footnoteFile, $this->getWriterPart('footnotes')->writeFootnotes($_allFootnotesCollection)); + if (count($footnoteLinks) > 0) { + $objZip->addFromString('word/_rels/footnotes.xml.rels', $this->getWriterPart('footnotesrels')->writeFootnotesRels($footnoteLinks)); + } + } + // build docx file // Write dynamic files $objZip->addFromString('[Content_Types].xml', $this->getWriterPart('contenttypes')->writeContentTypes($this->_imageTypes, $this->_objectTypes, $_cHdrs, $_cFtrs)); diff --git a/Classes/PHPWord/Writer/Word2007/Base.php b/Classes/PHPWord/Writer/Word2007/Base.php index 3d46444979..77f4d0d7fa 100755 --- a/Classes/PHPWord/Writer/Word2007/Base.php +++ b/Classes/PHPWord/Writer/Word2007/Base.php @@ -106,6 +106,10 @@ protected function _writeTextRun(PHPWord_Shared_XMLWriter $objWriter = null, PHP $this->_writeText($objWriter, $element, true); } elseif ($element instanceof PHPWord_Section_Link) { $this->_writeLink($objWriter, $element, true); + } elseif ($element instanceof PHPWord_Section_Image) { + $this->_writeImage($objWriter, $element, true); + } elseif($element instanceof PHPWord_Section_Footnote) { + $this->_writeFootnoteReference($objWriter, $element, true); } } } @@ -113,34 +117,62 @@ protected function _writeTextRun(PHPWord_Shared_XMLWriter $objWriter = null, PHP $objWriter->endElement(); } - protected function _writeParagraphStyle(PHPWord_Shared_XMLWriter $objWriter = null, PHPWord_Style_Paragraph $style, $withoutPPR = false) + /** + * Write paragraph style + * + * @param PHPWord_Shared_XMLWriter $objWriter + * @param PHPWord_Style_Paragraph $style + * @param bool $withoutPPR + * @return void + */ + protected function _writeParagraphStyle( + PHPWord_Shared_XMLWriter $objWriter = null, + PHPWord_Style_Paragraph $style, + $withoutPPR = false) { $align = $style->getAlign(); + $spacing = $style->getSpacing(); $spaceBefore = $style->getSpaceBefore(); $spaceAfter = $style->getSpaceAfter(); - $spacing = $style->getSpacing(); $indent = $style->getIndent(); + $hanging = $style->getHanging(); $tabs = $style->getTabs(); - - if (!is_null($align) || !is_null($spacing) || !is_null($spaceBefore) || !is_null($spaceAfter) || !is_null($indent) || !is_null($tabs)) { + $widowControl = $style->getWidowControl(); + $keepNext = $style->getKeepNext(); + $keepLines = $style->getKeepLines(); + $pageBreakBefore = $style->getPageBreakBefore(); + + if (!is_null($align) || !is_null($spacing) || !is_null($spaceBefore) || + !is_null($spaceAfter) || !is_null($indent) || !is_null($hanging) || + !is_null($tabs) || !is_null($widowControl) || !is_null($keepNext) || + !is_null($keepLines) || !is_null($pageBreakBefore)) { if (!$withoutPPR) { $objWriter->startElement('w:pPr'); } + // Alignment if (!is_null($align)) { $objWriter->startElement('w:jc'); $objWriter->writeAttribute('w:val', $align); $objWriter->endElement(); } - if (!is_null($indent)) { + // Indentation + if (!is_null($indent) || !is_null($hanging)) { $objWriter->startElement('w:ind'); $objWriter->writeAttribute('w:firstLine', 0); - $objWriter->writeAttribute('w:left', $indent); + if (!is_null($indent)) { + $objWriter->writeAttribute('w:left', $indent); + } + if (!is_null($hanging)) { + $objWriter->writeAttribute('w:hanging', $hanging); + } $objWriter->endElement(); } - if (!is_null($spaceBefore) || !is_null($spaceAfter) || !is_null($spacing)) { + // Spacing + if (!is_null($spaceBefore) || !is_null($spaceAfter) || + !is_null($spacing)) { $objWriter->startElement('w:spacing'); if (!is_null($spaceBefore)) { $objWriter->writeAttribute('w:before', $spaceBefore); @@ -155,6 +187,29 @@ protected function _writeParagraphStyle(PHPWord_Shared_XMLWriter $objWriter = nu $objWriter->endElement(); } + // Pagination + if (!$widowControl) { + $objWriter->startElement('w:widowControl'); + $objWriter->writeAttribute('w:val', '0'); + $objWriter->endElement(); + } + if ($keepNext) { + $objWriter->startElement('w:keepNext'); + $objWriter->writeAttribute('w:val', '1'); + $objWriter->endElement(); + } + if ($keepLines) { + $objWriter->startElement('w:keepLines'); + $objWriter->writeAttribute('w:val', '1'); + $objWriter->endElement(); + } + if ($pageBreakBefore) { + $objWriter->startElement('w:pageBreakBefore'); + $objWriter->writeAttribute('w:val', '1'); + $objWriter->endElement(); + } + + // Tabs if (!is_null($tabs)) { $tabs->toXml($objWriter); } @@ -318,13 +373,15 @@ protected function _writeTextStyle(PHPWord_Shared_XMLWriter $objWriter = null, P $color = $style->getColor(); $size = $style->getSize(); $fgColor = $style->getFgColor(); - $striketrough = $style->getStrikethrough(); + $strikethrough = $style->getStrikethrough(); $underline = $style->getUnderline(); + $superscript = $style->getSuperScript(); + $subscript = $style->getSubScript(); $objWriter->startElement('w:rPr'); // Font - if ($font != 'Arial') { + if ($font != PHPWord::DEFAULT_FONT_NAME) { $objWriter->startElement('w:rFonts'); $objWriter->writeAttribute('w:ascii', $font); $objWriter->writeAttribute('w:hAnsi', $font); @@ -333,19 +390,19 @@ protected function _writeTextStyle(PHPWord_Shared_XMLWriter $objWriter = null, P } // Color - if ($color != '000000') { + if ($color != PHPWord::DEFAULT_FONT_COLOR) { $objWriter->startElement('w:color'); $objWriter->writeAttribute('w:val', $color); $objWriter->endElement(); } // Size - if ($size != 20) { + if ($size != PHPWord::DEFAULT_FONT_SIZE) { $objWriter->startElement('w:sz'); - $objWriter->writeAttribute('w:val', $size); + $objWriter->writeAttribute('w:val', $size * 2); $objWriter->endElement(); $objWriter->startElement('w:szCs'); - $objWriter->writeAttribute('w:val', $size); + $objWriter->writeAttribute('w:val', $size * 2); $objWriter->endElement(); } @@ -367,8 +424,8 @@ protected function _writeTextStyle(PHPWord_Shared_XMLWriter $objWriter = null, P $objWriter->endElement(); } - // Striketrough - if ($striketrough) { + // Strikethrough + if ($strikethrough) { $objWriter->writeElement('w:strike', null); } @@ -379,6 +436,13 @@ protected function _writeTextStyle(PHPWord_Shared_XMLWriter $objWriter = null, P $objWriter->endElement(); } + // Superscript/subscript + if ($superscript || $subscript) { + $objWriter->startElement('w:vertAlign'); + $objWriter->writeAttribute('w:val', $superscript ? 'superscript' : 'subscript'); + $objWriter->endElement(); + } + $objWriter->endElement(); } @@ -395,6 +459,7 @@ protected function _writeTable(PHPWord_Shared_XMLWriter $objWriter = null, PHPWo if ($_cRows > 0) { $objWriter->startElement('w:tbl'); $tblStyle = $table->getStyle(); + $tblWidth = $table->getWidth(); if ($tblStyle instanceof PHPWord_Style_Table) { $this->_writeTableStyle($objWriter, $tblStyle); } else { @@ -403,26 +468,46 @@ protected function _writeTable(PHPWord_Shared_XMLWriter $objWriter = null, PHPWo $objWriter->startElement('w:tblStyle'); $objWriter->writeAttribute('w:val', $tblStyle); $objWriter->endElement(); + if (!is_null($tblWidth)) { + $objWriter->startElement('w:tblW'); + $objWriter->writeAttribute('w:w', $tblWidth); + $objWriter->writeAttribute('w:type', 'pct'); + $objWriter->endElement(); + } $objWriter->endElement(); } } - $_heights = $table->getRowHeights(); for ($i = 0; $i < $_cRows; $i++) { $row = $_rows[$i]; - $height = $_heights[$i]; + $height = $row->getHeight(); + $rowStyle = $row->getStyle(); + $tblHeader = $rowStyle->getTblHeader(); + $cantSplit = $rowStyle->getCantSplit(); $objWriter->startElement('w:tr'); - if (!is_null($height)) { + if (!is_null($height) || !is_null($tblHeader) || !is_null($cantSplit)) { $objWriter->startElement('w:trPr'); - $objWriter->startElement('w:trHeight'); - $objWriter->writeAttribute('w:val', $height); - $objWriter->endElement(); + if (!is_null($height)) { + $objWriter->startElement('w:trHeight'); + $objWriter->writeAttribute('w:val', $height); + $objWriter->endElement(); + } + if (!is_null($tblHeader)) { + $objWriter->startElement('w:tblHeader'); + $objWriter->writeAttribute('w:val', $tblHeader); + $objWriter->endElement(); + } + if (!is_null($cantSplit)) { + $objWriter->startElement('w:cantSplit'); + $objWriter->writeAttribute('w:val', $cantSplit); + $objWriter->endElement(); + } $objWriter->endElement(); } - foreach ($row as $cell) { + foreach ($row->getCells() as $cell) { $objWriter->startElement('w:tc'); $cellStyle = $cell->getStyle(); @@ -627,7 +712,7 @@ protected function _writeCellStyle(PHPWord_Shared_XMLWriter $objWriter = null, P * @param \PHPWord_Shared_XMLWriter $objWriter * @param \PHPWord_Section_Image $image */ - protected function _writeImage(PHPWord_Shared_XMLWriter $objWriter = null, PHPWord_Section_Image $image) + protected function _writeImage(PHPWord_Shared_XMLWriter $objWriter = null, PHPWord_Section_Image $image, $withoutP = false) { $rId = $image->getRelationId(); @@ -639,14 +724,16 @@ protected function _writeImage(PHPWord_Shared_XMLWriter $objWriter = null, PHPWo $marginLeft = $style->getMarginLeft(); $wrappingStyle = $style->getWrappingStyle(); - $objWriter->startElement('w:p'); + if (!$withoutP) { + $objWriter->startElement('w:p'); - if (!is_null($align)) { - $objWriter->startElement('w:pPr'); - $objWriter->startElement('w:jc'); - $objWriter->writeAttribute('w:val', $align); - $objWriter->endElement(); - $objWriter->endElement(); + if (!is_null($align)) { + $objWriter->startElement('w:pPr'); + $objWriter->startElement('w:jc'); + $objWriter->writeAttribute('w:val', $align); + $objWriter->endElement(); + $objWriter->endElement(); + } } $objWriter->startElement('w:r'); @@ -697,7 +784,9 @@ protected function _writeImage(PHPWord_Shared_XMLWriter $objWriter = null, PHPWo $objWriter->endElement(); - $objWriter->endElement(); + if (!$withoutP) { + $objWriter->endElement(); // w:p + } } protected function _writeWatermark(PHPWord_Shared_XMLWriter $objWriter = null, $image) @@ -785,4 +874,56 @@ protected function _writeTitle(PHPWord_Shared_XMLWriter $objWriter = null, PHPWo $objWriter->endElement(); } + + protected function _writeFootnote(PHPWord_Shared_XMLWriter $objWriter = null, PHPWord_Section_Footnote $footnote) { + $objWriter->startElement('w:footnote'); + $objWriter->writeAttribute('w:id', $footnote->getReferenceId()); + + $styleParagraph = $footnote->getParagraphStyle(); + $SpIsObject = ($styleParagraph instanceof PHPWord_Style_Paragraph) ? true : false; + + $objWriter->startElement('w:p'); + + if($SpIsObject) { + $this->_writeParagraphStyle($objWriter, $styleParagraph); + } elseif(!$SpIsObject && !is_null($styleParagraph)) { + $objWriter->startElement('w:pPr'); + $objWriter->startElement('w:pStyle'); + $objWriter->writeAttribute('w:val', $styleParagraph); + $objWriter->endElement(); + $objWriter->endElement(); + } + + $elements = $footnote->getElements(); + if(count($elements) > 0) { + foreach($elements as $element) { + if($element instanceof PHPWord_Section_Text) { + $this->_writeText($objWriter, $element, true); + } elseif($element instanceof PHPWord_Section_Link) { + $this->_writeLink($objWriter, $element, true); + } + } + } + + $objWriter->endElement(); // w:p + $objWriter->endElement(); // w:footnote + } + + protected function _writeFootnoteReference(PHPWord_Shared_XMLWriter $objWriter = null, PHPWord_Section_Footnote $footnote, $withoutP = false) { + if (!$withoutP) { + $objWriter->startElement('w:p'); + } + + $objWriter->startElement('w:r'); + + $objWriter->startElement('w:footnoteReference'); + $objWriter->writeAttribute('w:id', $footnote->getReferenceId()); + $objWriter->endElement(); // w:footnoteReference + + $objWriter->endElement(); // w:r + + if (!$withoutP) { + $objWriter->endElement(); // w:p + } + } } \ No newline at end of file diff --git a/Classes/PHPWord/Writer/Word2007/Document.php b/Classes/PHPWord/Writer/Word2007/Document.php index 41718f6e64..044dbceca2 100755 --- a/Classes/PHPWord/Writer/Word2007/Document.php +++ b/Classes/PHPWord/Writer/Word2007/Document.php @@ -94,6 +94,8 @@ public function writeDocument(PHPWord $pPHPWord = null) $this->_writeObject($objWriter, $element); } elseif ($element instanceof PHPWord_TOC) { $this->_writeTOC($objWriter); + } elseif($element instanceof PHPWord_Section_Footnote) { + $this->_writeFootnoteReference($objWriter, $element); } } @@ -135,8 +137,15 @@ private function _writeEndSection(PHPWord_Shared_XMLWriter $objWriter = null, PH $marginRight = $settings->getMarginRight(); $marginBottom = $settings->getMarginBottom(); + $headerHeight = $settings->getHeaderHeight(); + $footerHeight = $settings->getFooterHeight(); + $borders = $settings->getBorderSize(); + $colsNum = $settings->getColsNum(); + $colsSpace = $settings->getColsSpace(); + $breakType = $settings->getBreakType(); + $objWriter->startElement('w:sectPr'); foreach ($_headers as &$_header) { @@ -152,6 +161,12 @@ private function _writeEndSection(PHPWord_Shared_XMLWriter $objWriter = null, PH $objWriter->endElement(); } + if (!is_null($breakType)) { + $objWriter->startElement('w:type'); + $objWriter->writeAttribute('w:val', $breakType); + $objWriter->endElement(); + } + if (!is_null($_footer)) { $rId = $_footer->getRelationId(); $objWriter->startElement('w:footerReference'); @@ -175,8 +190,8 @@ private function _writeEndSection(PHPWord_Shared_XMLWriter $objWriter = null, PH $objWriter->writeAttribute('w:right', $marginRight); $objWriter->writeAttribute('w:bottom', $marginBottom); $objWriter->writeAttribute('w:left', $marginLeft); - $objWriter->writeAttribute('w:header', '720'); - $objWriter->writeAttribute('w:footer', '720'); + $objWriter->writeAttribute('w:header', $headerHeight); + $objWriter->writeAttribute('w:footer', $footerHeight); $objWriter->writeAttribute('w:gutter', '0'); $objWriter->endElement(); @@ -233,7 +248,8 @@ private function _writeEndSection(PHPWord_Shared_XMLWriter $objWriter = null, PH } $objWriter->startElement('w:cols'); - $objWriter->writeAttribute('w:space', '720'); + $objWriter->writeAttribute('w:num', $colsNum); + $objWriter->writeAttribute('w:space', $colsSpace); $objWriter->endElement(); diff --git a/Classes/PHPWord/Writer/Word2007/Footnotes.php b/Classes/PHPWord/Writer/Word2007/Footnotes.php new file mode 100644 index 0000000000..1bf27ee429 --- /dev/null +++ b/Classes/PHPWord/Writer/Word2007/Footnotes.php @@ -0,0 +1,81 @@ +getParentWriter()->getUseDiskCaching()) { + $objWriter = new PHPWord_Shared_XMLWriter(PHPWord_Shared_XMLWriter::STORAGE_DISK, $this->getParentWriter()->getDiskCachingDirectory()); + } else { + $objWriter = new PHPWord_Shared_XMLWriter(PHPWord_Shared_XMLWriter::STORAGE_MEMORY); + } + + // XML header + $objWriter->startDocument('1.0', 'UTF-8', 'yes'); + + $objWriter->startElement('w:footnotes'); + $objWriter->writeAttribute('xmlns:r','http://schemas.openxmlformats.org/officeDocument/2006/relationships'); + $objWriter->writeAttribute('xmlns:w','http://schemas.openxmlformats.org/wordprocessingml/2006/main'); + + // write separator and continuation separator + $objWriter->startElement('w:footnote'); + $objWriter->writeAttribute('w:id', 0); + $objWriter->writeAttribute('w:type', 'separator'); + $objWriter->startElement('w:p'); + $objWriter->startElement('w:r'); + $objWriter->startElement('w:separator'); + $objWriter->endElement(); // w:separator + $objWriter->endElement(); // w:r + $objWriter->endElement(); // w:p + $objWriter->endElement(); // w:footnote + + $objWriter->startElement('w:footnote'); + $objWriter->writeAttribute('w:id', 1); + $objWriter->writeAttribute('w:type', 'continuationSeparator'); + $objWriter->startElement('w:p'); + $objWriter->startElement('w:r'); + $objWriter->startElement('w:continuationSeparator'); + $objWriter->endElement(); // w:continuationSeparator + $objWriter->endElement(); // w:r + $objWriter->endElement(); // w:p + $objWriter->endElement(); // w:footnote + + + foreach($allFootnotesCollection as $footnote) { + if($footnote instanceof PHPWord_Section_Footnote) { + $this->_writeFootnote($objWriter, $footnote); + } + } + + $objWriter->endElement(); + + // Return + return $objWriter->getData(); + } +} \ No newline at end of file diff --git a/Classes/PHPWord/Writer/Word2007/FootnotesRels.php b/Classes/PHPWord/Writer/Word2007/FootnotesRels.php new file mode 100644 index 0000000000..22533815c2 --- /dev/null +++ b/Classes/PHPWord/Writer/Word2007/FootnotesRels.php @@ -0,0 +1,89 @@ +getParentWriter()->getUseDiskCaching()) { + $objWriter = new PHPWord_Shared_XMLWriter(PHPWord_Shared_XMLWriter::STORAGE_DISK, $this->getParentWriter()->getDiskCachingDirectory()); + } else { + $objWriter = new PHPWord_Shared_XMLWriter(PHPWord_Shared_XMLWriter::STORAGE_MEMORY); + } + + // XML header + $objWriter->startDocument('1.0','UTF-8','yes'); + + // Relationships + $objWriter->startElement('Relationships'); + $objWriter->writeAttribute('xmlns', 'http://schemas.openxmlformats.org/package/2006/relationships'); + + // Relationships to Links + foreach($_relsCollection as $relation) { + $relationType = $relation['type']; + $relationName = $relation['target']; + $relationId = $relation['rID']; + $targetMode = ($relationType == 'hyperlink') ? 'External' : ''; + + $this->_writeRelationship( + $objWriter, + $relationId, + 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/'.$relationType, + $relationName, + $targetMode + ); + } + + $objWriter->endElement(); + + // Return + return $objWriter->getData(); + } + + private function _writeRelationship(PHPWord_Shared_XMLWriter $objWriter = null, $pId = 1, $pType = '', $pTarget = '', $pTargetMode = '') { + if($pType != '' && $pTarget != '') { + if(strpos($pId, 'rId') === false) { + $pId = 'rId' . $pId; + } + + // Write relationship + $objWriter->startElement('Relationship'); + $objWriter->writeAttribute('Id', $pId); + $objWriter->writeAttribute('Type', $pType); + $objWriter->writeAttribute('Target', $pTarget); + + if($pTargetMode != '') { + $objWriter->writeAttribute('TargetMode', $pTargetMode); + } + + $objWriter->endElement(); + } else { + throw new Exception("Invalid parameters passed."); + } + } +} \ No newline at end of file diff --git a/Classes/PHPWord/Writer/Word2007/Styles.php b/Classes/PHPWord/Writer/Word2007/Styles.php index d2e285390b..c87d94bfa2 100755 --- a/Classes/PHPWord/Writer/Word2007/Styles.php +++ b/Classes/PHPWord/Writer/Word2007/Styles.php @@ -59,8 +59,30 @@ public function writeStyles(PHPWord $pPHPWord = null) // Write Style Definitions $styles = PHPWord_Style::getStyles(); + + // Write normal paragraph style + $normalStyle = null; + if (array_key_exists('Normal', $styles)) { + $normalStyle = $styles['Normal']; + } + $objWriter->startElement('w:style'); + $objWriter->writeAttribute('w:type', 'paragraph'); + $objWriter->writeAttribute('w:default', '1'); + $objWriter->writeAttribute('w:styleId', 'Normal'); + $objWriter->startElement('w:name'); + $objWriter->writeAttribute('w:val', 'Normal'); + $objWriter->endElement(); + if (!is_null($normalStyle)) { + $this->_writeParagraphStyle($objWriter, $normalStyle); + } + $objWriter->endElement(); + + // Write other styles if (count($styles) > 0) { foreach ($styles as $styleName => $style) { + if ($styleName == 'Normal') { + continue; + } if ($style instanceof PHPWord_Style_Font) { $paragraphStyle = $style->getParagraphStyle(); @@ -92,6 +114,10 @@ public function writeStyles(PHPWord $pPHPWord = null) $objWriter->endElement(); if (!is_null($paragraphStyle)) { + // Point parent style to Normal + $objWriter->startElement('w:basedOn'); + $objWriter->writeAttribute('w:val', 'Normal'); + $objWriter->endElement(); $this->_writeParagraphStyle($objWriter, $paragraphStyle); } @@ -109,6 +135,22 @@ public function writeStyles(PHPWord $pPHPWord = null) $objWriter->writeAttribute('w:val', $styleName); $objWriter->endElement(); + // Parent style + $basedOn = $style->getBasedOn(); + if (!is_null($basedOn)) { + $objWriter->startElement('w:basedOn'); + $objWriter->writeAttribute('w:val', $basedOn); + $objWriter->endElement(); + } + + // Next paragraph style + $next = $style->getNext(); + if (!is_null($next)) { + $objWriter->startElement('w:next'); + $objWriter->writeAttribute('w:val', $next); + $objWriter->endElement(); + } + $this->_writeParagraphStyle($objWriter, $style); $objWriter->endElement(); @@ -338,11 +380,11 @@ private function _writeDocDefaults(PHPWord_Shared_XMLWriter $objWriter = null) $objWriter->endElement(); $objWriter->startElement('w:sz'); - $objWriter->writeAttribute('w:val', $fontSize); + $objWriter->writeAttribute('w:val', $fontSize * 2); $objWriter->endElement(); $objWriter->startElement('w:szCs'); - $objWriter->writeAttribute('w:val', $fontSize); + $objWriter->writeAttribute('w:val', $fontSize * 2); $objWriter->endElement(); $objWriter->endElement(); diff --git a/README.md b/README.md index dc1a611a68..2f02013e77 100755 --- a/README.md +++ b/README.md @@ -34,11 +34,14 @@ the following lines to your ``composer.json``. ### Table of contents 1. [Basic usage](#basic-usage) + * [Measurement units](#measurement-units) 2. [Sections](#sections) - * [Change Section Page Numbering](#sections-page-numbering) -3. [Tables](#tables) + * [Section settings](#section-settings) + * [Section page numbering](#section-page-numbering) +3. [Texts](#texts) +4. [Tables](#tables) * [Cell Style](#tables-cell-style) -4. [Images](#images) +5. [Images](#images) #### Basic usage @@ -48,36 +51,106 @@ The following is a basic example of the PHPWord library. ```php $PHPWord = new PHPWord(); -// Every element you want to append to the word document is placed in a section. So you need a section: +// Every element you want to append to the word document is placed in a section. +// To create a basic section: $section = $PHPWord->createSection(); // After creating a section, you can append elements: $section->addText('Hello world!'); // You can directly style your text by giving the addText function an array: -$section->addText('Hello world! I am formatted.', array('name'=>'Tahoma', 'size'=>16, 'bold'=>true)); - -// If you often need the same style again you can create a user defined style to the word document -// and give the addText function the name of the style: -$PHPWord->addFontStyle('myOwnStyle', array('name'=>'Verdana', 'size'=>14, 'color'=>'1B2232')); -$section->addText('Hello world! I am formatted by a user defined style', 'myOwnStyle'); - -// You can also putthe appended element to local object an call functions like this: +$section->addText('Hello world! I am formatted.', + array('name'=>'Tahoma', 'size'=>16, 'bold'=>true)); + +// If you often need the same style again you can create a user defined style +// to the word document and give the addText function the name of the style: +$PHPWord->addFontStyle('myOwnStyle', + array('name'=>'Verdana', 'size'=>14, 'color'=>'1B2232')); +$section->addText('Hello world! I am formatted by a user defined style', + 'myOwnStyle'); + +// You can also put the appended element to local object like this: +$fontStyle = new PHPWord_Style_Font(); +$fontStyle->setBold(true); +$fontStyle->setName('Verdana'); +$fontStyle->setSize(22); $myTextElement = $section->addText('Hello World!'); -$myTextElement->setBold(); -$myTextElement->setName('Verdana'); -$myTextElement->setSize(22); +$myTextElement->setFontStyle($fontStyle); -// At least write the document to webspace: +// Finally, write the document: $objWriter = PHPWord_IOFactory::createWriter($PHPWord, 'Word2007'); $objWriter->save('helloWorld.docx'); ``` + +##### Measurement units + +The base length unit in Open Office XML is twip. Twip means "TWentieth of an Inch Point", i.e. 1 twip = 1/1440 inch. + +You can use PHPWord helper functions to convert inches, centimeters, or points to twips. + +```php +// Paragraph with 6 points space after +$PHPWord->addParagraphStyle('My Style', array( + 'spaceAfter' => PHPWord_Shared_Font::pointSizeToTwips(6)) +); + +$section = $PHPWord->createSection(); +$sectionStyle = $section->getSettings(); +// half inch left margin +$sectionStyle->setMarginLeft(PHPWord_Shared_Font::inchSizeToTwips(.5)); +// 2 cm right margin +$sectionStyle->setMarginRight(PHPWord_Shared_Font::centimeterSizeToTwips(2)); +``` + #### Sections - -##### Change Section Page Numbering +Every visible element in word is placed inside of a section. To create a section, use the following code: + +```php +$section = $PHPWord->createSection($sectionSettings); +``` +The `$sectionSettings` is an optional associative array that sets the section. Example: + +```php +$sectionSettings = array( + 'orientation' => 'landscape', + 'marginTop' => 600, + 'colsNum' => 2, +); +``` + +##### Section settings + +Below are the available settings for section: + +* `orientation` Page orientation, i.e. 'portrait' (default) or 'landscape' +* `marginTop` Page margin top in twips +* `marginLeft` Page margin left in twips +* `marginRight` Page margin right in twips +* `marginBottom` Page margin bottom in twips +* `borderTopSize` Border top size in twips +* `borderTopColor` Border top color +* `borderLeftSize` Border left size in twips +* `borderLeftColor` Border left color +* `borderRightSize` Border right size in twips +* `borderRightColor` Border right color +* `borderBottomSize` Border bottom size in twips +* `borderBottomColor` Border bottom color +* `headerHeight` Spacing to top of header +* `footerHeight` Spacing to bottom of footer +* `colsNum` Number of columns +* `colsSpace` Spacing between columns +* `breakType` Section break type (nextPage, nextColumn, continuous, evenPage, oddPage) + +The following two settings are automatically set by the use of the `orientation` setting. You can alter them but that's not recommended. + +* `pageSizeW` Page width in twips +* `pageSizeH` Page height in twips + + +##### Section page numbering You can change a section page numbering. @@ -86,6 +159,27 @@ $section = $PHPWord->createSection(); $section->getSettings()->setPageNumberingStart(1); ``` + +#### Texts + +Text can be added by using `addText` and `createTextRun` method. `addText` is used for creating simple paragraphs that only contain texts with the same style. `createTextRun` is used for creating complex paragraphs that contain text with different style (some bold, other italics, etc) or other elements, e.g. images or links. + +`addText` sample: + +```php +$fontStyle = array('name' => 'Times New Roman', 'size' => 9); +$paragraphStyle = array('align' => 'both'); +$section->addText('I am simple paragraph', $fontStyle, $paragraphStyle); +``` + +`createTextRun` sample: + +```php +$textrun = $section->createTextRun(); +$textrun->addText('I am bold', array('bold' => true)); +$textrun->addText('I am italic, array('italic' => true)); +$textrun->addText('I am colored, array('color' => 'AACC00')); +``` #### Tables diff --git a/Tests/PHPWord/IOFactoryTest.php b/Tests/PHPWord/IOFactoryTest.php index f6f0aba8ce..a7c05bcf47 100644 --- a/Tests/PHPWord/IOFactoryTest.php +++ b/Tests/PHPWord/IOFactoryTest.php @@ -5,55 +5,58 @@ use PHPWord; use PHPWord_IOFactory; use PHPWord_Writer_Word2007; +use Exception; /** - * Class PHPWord_IOFactoryTest + * Class IOFactoryTest * @package PHPWord\Tests * @runTestsInSeparateProcesses */ -class PHPWord_IOFactoryTest extends \PHPUnit_Framework_TestCase { - public function testGetSearchLocations() - { - $this->assertAttributeEquals(PHPWord_IOFactory::getSearchLocations(), '_searchLocations','PHPWord_IOFactory'); - } - - public function testSetSearchLocationsWithArray() - { - PHPWord_IOFactory::setSearchLocations(array()); - $this->assertAttributeEquals(array(), '_searchLocations','PHPWord_IOFactory'); - } - - /** - * @expectedException Exception - * @expectedExceptionMessage Invalid parameter passed. - */ - public function testSetSearchLocationsWithNotArray() - { - PHPWord_IOFactory::setSearchLocations('String'); - } - - public function testAddSearchLocation() - { - PHPWord_IOFactory::setSearchLocations(array()); - PHPWord_IOFactory::addSearchLocation('type', 'location', 'classname'); - $this->assertAttributeEquals(array(array('type' => 'type', 'path' => 'location', 'class' => 'classname')), '_searchLocations','PHPWord_IOFactory'); - } - - /** - * @expectedException Exception - * @expectedExceptionMessage No IWriter found for type - */ - public function testCreateWriterException(){ - $oPHPWord = new PHPWord(); - - PHPWord_IOFactory::setSearchLocations(array()); - PHPWord_IOFactory::createWriter($oPHPWord); - } - - public function testCreateWriter(){ - $oPHPWord = new PHPWord(); - - $this->assertEquals(PHPWord_IOFactory::createWriter($oPHPWord, 'Word2007'), new PHPWord_Writer_Word2007($oPHPWord)); - } -} - \ No newline at end of file +class IOFactoryTest extends \PHPUnit_Framework_TestCase +{ + public function testGetSearchLocations() + { + $this->assertAttributeEquals(PHPWord_IOFactory::getSearchLocations(), '_searchLocations', 'PHPWord_IOFactory'); + } + + public function testSetSearchLocationsWithArray() + { + PHPWord_IOFactory::setSearchLocations(array()); + $this->assertAttributeEquals(array(), '_searchLocations', 'PHPWord_IOFactory'); + } + + /** + * @expectedException Exception + * @expectedExceptionMessage Invalid parameter passed. + */ + public function testSetSearchLocationsWithNotArray() + { + PHPWord_IOFactory::setSearchLocations('String'); + } + + public function testAddSearchLocation() + { + PHPWord_IOFactory::setSearchLocations(array()); + PHPWord_IOFactory::addSearchLocation('type', 'location', 'classname'); + $this->assertAttributeEquals(array(array('type' => 'type', 'path' => 'location', 'class' => 'classname')), '_searchLocations', 'PHPWord_IOFactory'); + } + + /** + * @expectedException Exception + * @expectedExceptionMessage No IWriter found for type + */ + public function testCreateWriterException() + { + $oPHPWord = new PHPWord(); + + PHPWord_IOFactory::setSearchLocations(array()); + PHPWord_IOFactory::createWriter($oPHPWord); + } + + public function testCreateWriter() + { + $oPHPWord = new PHPWord(); + + $this->assertEquals(PHPWord_IOFactory::createWriter($oPHPWord, 'Word2007'), new PHPWord_Writer_Word2007($oPHPWord)); + } +} \ No newline at end of file diff --git a/Tests/PHPWord/MediaTest.php b/Tests/PHPWord/MediaTest.php index 40460deace..25cdab0acf 100644 --- a/Tests/PHPWord/MediaTest.php +++ b/Tests/PHPWord/MediaTest.php @@ -4,26 +4,25 @@ use PHPUnit_Framework_TestCase; use PHPWord_Media; -class PHPWord_MediaTest extends \PHPUnit_Framework_TestCase { +class MediaTest extends \PHPUnit_Framework_TestCase +{ + public function testGetSectionMediaElementsWithNull() + { + $this->assertEquals(PHPWord_Media::getSectionMediaElements(), array()); + } - public function testGetSectionMediaElementsWithNull() - { - $this->assertEquals(PHPWord_Media::getSectionMediaElements(), array()); - } + public function testCountSectionMediaElementsWithNull() + { + $this->assertEquals(PHPWord_Media::countSectionMediaElements(), 0); + } - public function testCountSectionMediaElementsWithNull() - { - $this->assertEquals(PHPWord_Media::countSectionMediaElements(), 0); - } + public function testGetHeaderMediaElements() + { + $this->assertAttributeEquals(PHPWord_Media::getHeaderMediaElements(), '_headerMedia', 'PHPWord_Media'); + } - public function testGetHeaderMediaElements() - { - $this->assertAttributeEquals(PHPWord_Media::getHeaderMediaElements(), '_headerMedia','PHPWord_Media'); - } - - public function testGetFooterMediaElements() - { - $this->assertAttributeEquals(PHPWord_Media::getFooterMediaElements(), '_footerMedia','PHPWord_Media'); - } -} - \ No newline at end of file + public function testGetFooterMediaElements() + { + $this->assertAttributeEquals(PHPWord_Media::getFooterMediaElements(), '_footerMedia', 'PHPWord_Media'); + } +} \ No newline at end of file diff --git a/Tests/PHPWord/SectionTest.php b/Tests/PHPWord/SectionTest.php index 0e90961de1..378fd6425b 100644 --- a/Tests/PHPWord/SectionTest.php +++ b/Tests/PHPWord/SectionTest.php @@ -4,35 +4,35 @@ use PHPUnit_Framework_TestCase; use PHPWord_Section; -class PHPWord_SectionTest extends \PHPUnit_Framework_TestCase { - public function testGetSettings() - { - $oSection = new PHPWord_Section(0); - $this->assertAttributeEquals($oSection->getSettings(), '_settings', new PHPWord_Section(0)); - } +class SectionTest extends \PHPUnit_Framework_TestCase +{ + public function testGetSettings() + { + $oSection = new PHPWord_Section(0); + $this->assertAttributeEquals($oSection->getSettings(), '_settings', new PHPWord_Section(0)); + } - public function testGetElementss() - { - $oSection = new PHPWord_Section(0); - $this->assertAttributeEquals($oSection->getElements(), '_elementCollection',new PHPWord_Section(0)); - } + public function testGetElementss() + { + $oSection = new PHPWord_Section(0); + $this->assertAttributeEquals($oSection->getElements(), '_elementCollection', new PHPWord_Section(0)); + } - public function testGetFooter() - { - $oSection = new PHPWord_Section(0); - $this->assertAttributeEquals($oSection->getFooter(), '_footer',new PHPWord_Section(0)); - } + public function testGetFooter() + { + $oSection = new PHPWord_Section(0); + $this->assertAttributeEquals($oSection->getFooter(), '_footer', new PHPWord_Section(0)); + } - public function testGetHeaders() - { - $oSection = new PHPWord_Section(0); - $this->assertAttributeEquals($oSection->getHeaders(), '_headers',new PHPWord_Section(0)); - } + public function testGetHeaders() + { + $oSection = new PHPWord_Section(0); + $this->assertAttributeEquals($oSection->getHeaders(), '_headers', new PHPWord_Section(0)); + } - public function testGetElements() - { - $oSection = new PHPWord_Section(0); - $this->assertAttributeEquals($oSection->getElements(), '_elementCollection',new PHPWord_Section(0)); - } -} - \ No newline at end of file + public function testGetElements() + { + $oSection = new PHPWord_Section(0); + $this->assertAttributeEquals($oSection->getElements(), '_elementCollection', new PHPWord_Section(0)); + } +} \ No newline at end of file diff --git a/Tests/PHPWord/Shared/FontTest.php b/Tests/PHPWord/Shared/FontTest.php new file mode 100644 index 0000000000..09603d5fa0 --- /dev/null +++ b/Tests/PHPWord/Shared/FontTest.php @@ -0,0 +1,48 @@ +assertEquals($original * 16 / 12, $result); + + $result = PHPWord_Shared_Font::inchSizeToPixels($original); + $this->assertEquals($original * 96, $result); + + $result = PHPWord_Shared_Font::centimeterSizeToPixels($original); + $this->assertEquals($original * 37.795275591, $result); + + $result = PHPWord_Shared_Font::centimeterSizeToTwips($original); + $this->assertEquals($original * 565.217, $result); + + $result = PHPWord_Shared_Font::inchSizeToTwips($original); + $this->assertEquals($original * 565.217 * 2.54, $result); + + $result = PHPWord_Shared_Font::pixelSizeToTwips($original); + $this->assertEquals($original * 565.217 / 37.795275591, $result); + + $result = PHPWord_Shared_Font::pointSizeToTwips($original); + $this->assertEquals($original * 20, $result); + } + +} diff --git a/Tests/PHPWord/Style/CellTest.php b/Tests/PHPWord/Style/CellTest.php new file mode 100644 index 0000000000..4db86f3580 --- /dev/null +++ b/Tests/PHPWord/Style/CellTest.php @@ -0,0 +1,80 @@ + 'left', + 'textDirection' => PHPWord_Style_Cell::TEXT_DIR_BTLR, + 'bgColor' => 'FFFF00', + 'borderTopSize' => 120, + 'borderTopColor' => 'FFFF00', + 'borderLeftSize' => 120, + 'borderLeftColor' => 'FFFF00', + 'borderRightSize' => 120, + 'borderRightColor' => 'FFFF00', + 'borderBottomSize' => 120, + 'borderBottomColor' => 'FFFF00', + 'gridSpan' => 2, + 'vMerge' => 2, + ); + //'defaultBorderColor' => null, + foreach ($attributes as $key => $value) { + $set = "set{$key}"; + $get = "get{$key}"; + $object->$set($value); + $this->assertEquals($value, $object->$get()); + } + } + + /** + * Test border color + */ + public function testBorderColor() + { + $object = new PHPWord_Style_Cell(); + + $default = '000000'; + $value = 'FF0000'; + + $this->assertEquals($default, $object->getDefaultBorderColor()); + + $object->setStyleValue('_defaultBorderColor', $value); + $this->assertEquals($value, $object->getDefaultBorderColor()); + + $object->setStyleValue('_borderColor', $value); + $expected = array($value, $value, $value, $value); + $this->assertEquals($expected, $object->getBorderColor()); + } + + /** + * Test border size + */ + public function testBorderSize() + { + $object = new PHPWord_Style_Cell(); + + $value = 120; + $expected = array($value, $value, $value, $value); + $object->setStyleValue('_borderSize', $value); + $this->assertEquals($expected, $object->getBorderSize()); + } + +} diff --git a/Tests/PHPWord/Style/FontTest.php b/Tests/PHPWord/Style/FontTest.php new file mode 100644 index 0000000000..a3fa2086ab --- /dev/null +++ b/Tests/PHPWord/Style/FontTest.php @@ -0,0 +1,82 @@ + 'both')); + + $this->assertEquals('text', $object->getStyleType()); + $this->assertInstanceOf('PHPWord_Style_Paragraph', $object->getParagraphStyle()); + } + + /** + * Test setting style values with null or empty value + */ + public function testSetStyleValueWithNullOrEmpty() + { + $object = new PHPWord_Style_Font(); + + $attributes = array( + 'name' => PHPWord::DEFAULT_FONT_NAME, + 'size' => PHPWord::DEFAULT_FONT_SIZE, + 'bold' => false, + 'italic' => false, + 'superScript' => false, + 'subScript' => false, + 'underline' => PHPWord_Style_Font::UNDERLINE_NONE, + 'strikethrough' => false, + 'color' => PHPWord::DEFAULT_FONT_COLOR, + 'fgColor' => null, + ); + foreach ($attributes as $key => $default) { + $get = "get{$key}"; + $object->setStyleValue("_$key", null); + $this->assertEquals($default, $object->$get()); + $object->setStyleValue("_$key", ''); + $this->assertEquals($default, $object->$get()); + } + } + + /** + * Test setting style values with normal value + */ + public function testSetStyleValueNormal() + { + $object = new PHPWord_Style_Font(); + + $attributes = array( + 'name' => 'Times New Roman', + 'size' => 9, + 'bold' => true, + 'italic' => true, + 'superScript' => true, + 'subScript' => true, + 'underline' => PHPWord_Style_Font::UNDERLINE_HEAVY, + 'strikethrough' => true, + 'color' => '999999', + 'fgColor' => '999999', + ); + foreach ($attributes as $key => $value) { + $get = "get{$key}"; + $object->setStyleValue("_$key", $value); + $this->assertEquals($value, $object->$get()); + } + } + +} diff --git a/Tests/PHPWord/Style/ParagraphTest.php b/Tests/PHPWord/Style/ParagraphTest.php new file mode 100644 index 0000000000..bcfd4872f0 --- /dev/null +++ b/Tests/PHPWord/Style/ParagraphTest.php @@ -0,0 +1,53 @@ +createSection(); + + // Test style array + $text = $section->addText('This is a test', array(), array( + 'line-height' => 2.0 + )); + + $doc = TestHelperDOCX::getDocument($PHPWord); + $element = $doc->getElement('/w:document/w:body/w:p/w:pPr/w:spacing'); + + $lineHeight = $element->getAttribute('w:line'); + $lineRule = $element->getAttribute('w:lineRule'); + + $this->assertEquals(480, $lineHeight); + $this->assertEquals('auto', $lineRule); + + // Test setter + $text->getParagraphStyle()->setLineHeight(3.0); + $doc = TestHelperDOCX::getDocument($PHPWord); + $element = $doc->getElement('/w:document/w:body/w:p/w:pPr/w:spacing'); + + $lineHeight = $element->getAttribute('w:line'); + $lineRule = $element->getAttribute('w:lineRule'); + + $this->assertEquals(720, $lineHeight); + $this->assertEquals('auto', $lineRule); + } +} diff --git a/Tests/PHPWord/TemplateTest.php b/Tests/PHPWord/TemplateTest.php new file mode 100644 index 0000000000..1cc30639a9 --- /dev/null +++ b/Tests/PHPWord/TemplateTest.php @@ -0,0 +1,118 @@ +load( + \join( + \DIRECTORY_SEPARATOR, + array(\PHPWORD_TESTS_DIR_ROOT, '_files', 'xsl', 'remove_tables_by_needle.xsl') + ) + ); + + foreach (array('${employee.', '${scoreboard.') as $needle) { + $template->applyXslStyleSheet($xslDOMDocument, array('needle' => $needle)); + } + + $actualDocument = $template->save(); + $expectedDocument = \join( + \DIRECTORY_SEPARATOR, + array(\PHPWORD_TESTS_DIR_ROOT, '_files', 'documents', 'without_table_macros.docx') + ); + + $actualZip = new \ZipArchive(); + $actualZip->open($actualDocument); + $actualXml = $actualZip->getFromName('word/document.xml'); + if ($actualZip->close() === false) { + throw new \Exception('Could not close zip file "' . $actualDocument . '".'); + } + + $expectedZip = new \ZipArchive(); + $expectedZip->open($expectedDocument); + $expectedXml = $expectedZip->getFromName('word/document.xml'); + if ($expectedZip->close() === false) { + throw new \Exception('Could not close zip file "' . $expectedDocument . '".'); + } + + $this->assertXmlStringEqualsXmlString($expectedXml, $actualXml); + } + + /** + * @covers ::applyXslStyleSheet + * @expectedException Exception + * @expectedExceptionMessage Could not set values for the given XSL style sheet parameters. + * @test + */ + final public function testXslStyleSheetCanNotBeAppliedOnFailureOfSettingParameterValue() + { + $template = new PHPWord_Template( + \join( + \DIRECTORY_SEPARATOR, + array(\PHPWORD_TESTS_DIR_ROOT, '_files', 'templates', 'blank.docx') + ) + ); + + $xslDOMDocument = new \DOMDocument(); + $xslDOMDocument->load( + \join( + \DIRECTORY_SEPARATOR, + array(\PHPWORD_TESTS_DIR_ROOT, '_files', 'xsl', 'passthrough.xsl') + ) + ); + + /* + * We have to use error control below, because XSLTProcessor::setParameter omits warning on failure. + * This warning fails the test. + */ + @$template->applyXslStyleSheet($xslDOMDocument, array(1 => 'somevalue')); + } + + /** + * @covers ::applyXslStyleSheet + * @expectedException Exception + * @expectedExceptionMessage Could not load XML from the given template. + * @test + */ + final public function testXslStyleSheetCanNotBeAppliedOnFailureOfLoadingXmlFromTemplate() + { + $template = new PHPWord_Template( + \join( + \DIRECTORY_SEPARATOR, + array(\PHPWORD_TESTS_DIR_ROOT, '_files', 'templates', 'corrupted_main_document_part.docx') + ) + ); + + $xslDOMDocument = new \DOMDocument(); + $xslDOMDocument->load( + \join( + \DIRECTORY_SEPARATOR, + array(\PHPWORD_TESTS_DIR_ROOT, '_files', 'xsl', 'passthrough.xsl') + ) + ); + + /* + * We have to use error control below, because DOMDocument::loadXML omits warning on failure. + * This warning fails the test. + */ + @$template->applyXslStyleSheet($xslDOMDocument); + } +} \ No newline at end of file diff --git a/Tests/PHPWord/Writer/Word2007/BaseTest.php b/Tests/PHPWord/Writer/Word2007/BaseTest.php index 8788af8b3e..9d2570eb8e 100644 --- a/Tests/PHPWord/Writer/Word2007/BaseTest.php +++ b/Tests/PHPWord/Writer/Word2007/BaseTest.php @@ -1,62 +1,62 @@ createSection(); - $section->addImage( - PHPWORD_TESTS_DIR_ROOT . '/_files/images/earth.jpg', - array( - 'marginTop' => -1, - 'marginLeft' => -1, - 'wrappingStyle' => 'behind' - ) - ); - - $doc = TestHelperDOCX::getDocument($PHPWord); - $element = $doc->getElement('/w:document/w:body/w:p/w:r/w:pict/v:shape'); - - $style = $element->getAttribute('style'); - - $this->assertRegExp('/z\-index:\-[0-9]*/', $style); - $this->assertRegExp('/position:absolute;/', $style); - } + public function testWriteImage_Position() + { + $PHPWord = new PHPWord(); + $section = $PHPWord->createSection(); + $section->addImage( + PHPWORD_TESTS_DIR_ROOT . '/_files/images/earth.jpg', + array( + 'marginTop' => -1, + 'marginLeft' => -1, + 'wrappingStyle' => 'behind' + ) + ); - public function testWriteParagraphStyle_Align() - { - $PHPWord = new PHPWord(); - $section = $PHPWord->createSection(); + $doc = TestHelperDOCX::getDocument($PHPWord); + $element = $doc->getElement('/w:document/w:body/w:p/w:r/w:pict/v:shape'); - $section->addText('This is my text', null, array('align' => 'right')); + $style = $element->getAttribute('style'); - $doc = TestHelperDOCX::getDocument($PHPWord); - $element = $doc->getElement('/w:document/w:body/w:p/w:pPr/w:jc'); + $this->assertRegExp('/z\-index:\-[0-9]*/', $style); + $this->assertRegExp('/position:absolute;/', $style); + } - $this->assertEquals('right', $element->getAttribute('w:val')); - } + public function testWriteParagraphStyle_Align() + { + $PHPWord = new PHPWord(); + $section = $PHPWord->createSection(); + + $section->addText('This is my text', null, array('align' => 'right')); - public function testWriteCellStyle_CellGridSpan() - { + $doc = TestHelperDOCX::getDocument($PHPWord); + $element = $doc->getElement('/w:document/w:body/w:p/w:pPr/w:jc'); + + $this->assertEquals('right', $element->getAttribute('w:val')); + } + + public function testWriteCellStyle_CellGridSpan() + { $PHPWord = new PHPWord(); $section = $PHPWord->createSection(); @@ -77,6 +77,36 @@ public function testWriteCellStyle_CellGridSpan() $element = $doc->getElement('/w:document/w:body/w:tbl/w:tr/w:tc/w:tcPr/w:gridSpan'); $this->assertEquals(5, $element->getAttribute('w:val')); + } + + /** + * Test write paragraph pagination + */ + public function testWriteParagraphStyle_Pagination() + { + // Create the doc + $PHPWord = new PHPWord(); + $section = $PHPWord->createSection(); + $attributes = array( + 'widowControl' => false, + 'keepNext' => true, + 'keepLines' => true, + 'pageBreakBefore' => true, + ); + foreach ($attributes as $attribute => $value) { + $section->addText('Test', null, array($attribute => $value)); + } + $doc = TestHelperDOCX::getDocument($PHPWord); + + // Test the attributes + $i = 0; + foreach ($attributes as $key => $value) { + $i++; + $path = "/w:document/w:body/w:p[{$i}]/w:pPr/w:{$key}"; + $element = $doc->getElement($path); + $expected = $value ? 1 : 0; + $this->assertEquals($expected, $element->getAttribute('w:val')); + } } + } - \ No newline at end of file diff --git a/Tests/PHPWord/Writer/Word2007/DocumentTest.php b/Tests/PHPWord/Writer/Word2007/DocumentTest.php index 13d233cce9..5d91ebabaa 100644 --- a/Tests/PHPWord/Writer/Word2007/DocumentTest.php +++ b/Tests/PHPWord/Writer/Word2007/DocumentTest.php @@ -1,35 +1,36 @@ createSection(); - $section->getSettings()->setPageNumberingStart(2); + public function testWriteEndSection_PageNumbering() + { + $PHPWord = new PHPWord(); + $section = $PHPWord->createSection(); + $section->getSettings()->setPageNumberingStart(2); - $doc = TestHelperDOCX::getDocument($PHPWord); - $element = $doc->getElement('/w:document/w:body/w:sectPr/w:pgNumType'); + $doc = TestHelperDOCX::getDocument($PHPWord); + $element = $doc->getElement('/w:document/w:body/w:sectPr/w:pgNumType'); - $this->assertEquals(2, $element->getAttribute('w:start')); - } -} - \ No newline at end of file + $this->assertEquals(2, $element->getAttribute('w:start')); + } +} \ No newline at end of file diff --git a/Tests/PHPWord/Writer/Word2007/StylesTest.php b/Tests/PHPWord/Writer/Word2007/StylesTest.php new file mode 100644 index 0000000000..42bde30f5a --- /dev/null +++ b/Tests/PHPWord/Writer/Word2007/StylesTest.php @@ -0,0 +1,55 @@ + 'both'); + $baseStyle = array('basedOn' => 'Normal'); + $newStyle = array('basedOn' => 'Base Style', 'next' => 'Normal'); + $PHPWord->setDefaultParagraphStyle($defaultStyle); + $PHPWord->addParagraphStyle('Base Style', $baseStyle); + $PHPWord->addParagraphStyle('New Style', $newStyle); + $doc = TestHelperDOCX::getDocument($PHPWord); + $file = 'word/styles.xml'; + + // Normal style generated? + $path = '/w:styles/w:style[@w:styleId="Normal"]/w:name'; + $element = $doc->getElement($path, $file); + $this->assertEquals('Normal', $element->getAttribute('w:val')); + + // Parent style referenced? + $path = '/w:styles/w:style[@w:styleId="New Style"]/w:basedOn'; + $element = $doc->getElement($path, $file); + $this->assertEquals('Base Style', $element->getAttribute('w:val')); + + // Next paragraph style correct? + $path = '/w:styles/w:style[@w:styleId="New Style"]/w:next'; + $element = $doc->getElement($path, $file); + $this->assertEquals('Normal', $element->getAttribute('w:val')); + } + +} diff --git a/Tests/_files/documents/without_table_macros.docx b/Tests/_files/documents/without_table_macros.docx new file mode 100644 index 0000000000..e4e9767fc1 Binary files /dev/null and b/Tests/_files/documents/without_table_macros.docx differ diff --git a/Tests/_files/templates/blank.docx b/Tests/_files/templates/blank.docx new file mode 100644 index 0000000000..071b7f350d Binary files /dev/null and b/Tests/_files/templates/blank.docx differ diff --git a/Tests/_files/templates/corrupted_main_document_part.docx b/Tests/_files/templates/corrupted_main_document_part.docx new file mode 100644 index 0000000000..69712525a4 Binary files /dev/null and b/Tests/_files/templates/corrupted_main_document_part.docx differ diff --git a/Tests/_files/templates/with_table_macros.docx b/Tests/_files/templates/with_table_macros.docx new file mode 100644 index 0000000000..cd5ed6cedb Binary files /dev/null and b/Tests/_files/templates/with_table_macros.docx differ diff --git a/Tests/_files/xsl/passthrough.xsl b/Tests/_files/xsl/passthrough.xsl new file mode 100644 index 0000000000..4ab21dd745 --- /dev/null +++ b/Tests/_files/xsl/passthrough.xsl @@ -0,0 +1,11 @@ + + + + + + + + + + \ No newline at end of file diff --git a/Tests/_files/xsl/remove_tables_by_needle.xsl b/Tests/_files/xsl/remove_tables_by_needle.xsl new file mode 100644 index 0000000000..1a7b13693d --- /dev/null +++ b/Tests/_files/xsl/remove_tables_by_needle.xsl @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/Tests/_inc/TestHelperDOCX.php b/Tests/_inc/TestHelperDOCX.php index 32f1af08bc..5c603b0b0e 100644 --- a/Tests/_inc/TestHelperDOCX.php +++ b/Tests/_inc/TestHelperDOCX.php @@ -25,7 +25,7 @@ public static function getDocument(PHPWord $PHPWord) $zip = new \ZipArchive; $res = $zip->open(self::$file); if ($res === true) { - $zip->extractTo(sys_get_temp_dir().'/PHPWord_Unit_Test/'); + $zip->extractTo(sys_get_temp_dir() . '/PHPWord_Unit_Test/'); $zip->close(); } diff --git a/Tests/bootstrap.php b/Tests/bootstrap.php index 554dc38f22..916d3503c2 100755 --- a/Tests/bootstrap.php +++ b/Tests/bootstrap.php @@ -3,8 +3,8 @@ date_default_timezone_set('UTC'); // Constantes -if(!defined('PHPWORD_TESTS_DIR_ROOT')){ - define('PHPWORD_TESTS_DIR_ROOT', __DIR__); +if (!defined('PHPWORD_TESTS_DIR_ROOT')) { + define('PHPWORD_TESTS_DIR_ROOT', __DIR__); } // Includes diff --git a/changelog.txt b/changelog.txt index 7b5375b465..9b81b96798 100755 --- a/changelog.txt +++ b/changelog.txt @@ -25,9 +25,30 @@ Changes in branch for release 0.7.1 : - Bugfix: (gabrielbull) - Fixed bug with cell styling - Bugfix: (gabrielbull) - Fixed bug list items inside of cells +- Bugfix: (SiebelsTim) GH-51 - Adding a value that contains "&" in a template breaks it +- Bugfix: (Progi1984) GH-89 - Example in README.md is broken - Feature: (RomanSyroeshko) GH-56 GH-57 - Template : Permit to save a template generated as a file (PHPWord_Template::saveAs()) - Feature: (gabrielbull) - Word2007 : Support sections page numbering -- Feature: (gabrielbull) - Word2007 : Added support for line height +- Feature: (gabrielbull) - Word2007 : Added line height methods to mirror the line height settings in Word in the paragraph styling +- Feature: (JillElaine) GH-5 - Word2007 : Added support for page header & page footer height +- Feature: (bskrtich) GH-6 GH-66 GH-84 - General : Add ability to manage line breaks after image insertion +- Feature: (RomanSyroeshko) GH-52 GH-53 GH-85 - Template : Ability to limit number of replacements performed by setValue() method of Template class +- Feature: (ivanlanin) GH-48 GH-86 - Table row: Repeat as header row & allow row to break across pages +- Feature: (ivanlanin) GH-48 GH-86 - Table: Table width in percentage +- Feature: (ivanlanin) GH-48 GH-86 - Font: Superscript and subscript +- Feature: (ivanlanin) GH-48 GH-86 - Paragraph: Hanging paragraph +- Feature: (ivanlanin) GH-48 GH-86 - Section: Multicolumn and section break +- Feature: (RomanSyroeshko) GH-46 GH-47 GH-83 - Template : Ability to apply XSL style sheet to Template +- Feature: (ivanlanin) GH-87 - General: PHPWord_Shared_Font::pointSizeToTwips() converter +- Feature: (ivanlanin) GH-87 - Paragraph: Ability to define normal paragraph style with PHPWord::setNormalStyle() +- Feature: (ivanlanin) GH-87 - Paragraph: Ability to define parent style (basedOn) and style for following paragraph (next) +- Feature: (jeroenmoors) GH-44 GH-88 - Clone table rows on the fly when using a template document +- Feature: (deds) GH-16 - Initial addition of basic footnote support +- Feature: (ivanlanin) GH-92 - Paragraph: Ability to define paragraph pagination: widow control, keep next, keep lines, and page break before +- General: (ivanlanin) GH-93 - General: PHPWord_Style_Font refactoring +- General: (ivanlanin) GH-93 - Font: Use points instead of halfpoints internally. Conversion to halfpoints done during XML Writing. +- Bugfix: (ivanlanin) GH-94 - General: PHPWord_Shared_Drawing::centimetersToPixels() conversion +- Feature: (ivanlanin) - Paragraph: setTabs() function - QA: (Progi1984) - UnitTests Changes in branch for release 0.7.0 : diff --git a/phpunit.xml.dist b/phpunit.xml.dist index e57799ce6e..908304adea 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -15,7 +15,7 @@ - ../Classes + ./Classes diff --git a/samples/Sample_01_SimpleText.php b/samples/Sample_01_SimpleText.php index b2d6593a75..4b055cca8a 100755 --- a/samples/Sample_01_SimpleText.php +++ b/samples/Sample_01_SimpleText.php @@ -4,8 +4,7 @@ if(php_sapi_name() == 'cli' && empty($_SERVER['REMOTE_ADDR'])) { define('EOL', PHP_EOL); -} -else { +} else { define('EOL', '
'); } diff --git a/samples/Sample_03_Sections.php b/samples/Sample_03_Sections.php new file mode 100755 index 0000000000..d2231dfa6b --- /dev/null +++ b/samples/Sample_03_Sections.php @@ -0,0 +1,55 @@ +'); +} + +require_once '../Classes/PHPWord.php'; + +// New Word Document +echo date('H:i:s') , ' Create new PHPWord object' , EOL; +$PHPWord = new PHPWord(); + +// New portrait section +$section = $PHPWord->createSection(array('borderColor' => '00FF00', 'borderSize' => 12)); +$section->addText('I am placed on a default section.'); + +// New landscape section +$section = $PHPWord->createSection(array('orientation' => 'landscape')); +$section->addText('I am placed on a landscape section. Every page starting from this section will be landscape style.'); +$section->addPageBreak(); +$section->addPageBreak(); + +// New portrait section +$section = $PHPWord->createSection(array('marginLeft' => 600, 'marginRight' => 600, 'marginTop' => 600, 'marginBottom' => 600)); +$section->addText('This section uses other margins.'); + +// New portrait section with Header & Footer +$section = $PHPWord->createSection(array('marginLeft' => 200, 'marginRight' => 200, 'marginTop' => 200, 'marginBottom' => 200, 'headerHeight' => 50, 'footerHeight' => 50,)); +$section->addText('This section and we play with header/footer height.'); +$section->createHeader()->addText('Header'); +$section->createFooter()->addText('Footer'); + +// Save File +echo date('H:i:s') , ' Write to Word2007 format' , EOL; +$objWriter = PHPWord_IOFactory::createWriter($PHPWord, 'Word2007'); +$objWriter->save(str_replace('.php', '.docx', __FILE__)); + +/*echo date('H:i:s') , ' Write to OpenDocumentText format' , EOL; +$objWriter = PHPWord_IOFactory::createWriter($PHPWord, 'ODText'); +$objWriter->save(str_replace('.php', '.odt', __FILE__)); + +echo date('H:i:s') , ' Write to RTF format' , EOL; +$objWriter = PHPWord_IOFactory::createWriter($PHPWord, 'RTF'); +$objWriter->save(str_replace('.php', '.rtf', __FILE__));*/ + + +// Echo memory peak usage +echo date('H:i:s') , ' Peak memory usage: ' , (memory_get_peak_usage(true) / 1024 / 1024) , ' MB' , EOL; + +// Echo done +echo date('H:i:s') , ' Done writing file' , EOL; diff --git a/samples/Sample_04_Textrun.php b/samples/Sample_04_Textrun.php new file mode 100644 index 0000000000..164afc3cfe --- /dev/null +++ b/samples/Sample_04_Textrun.php @@ -0,0 +1,66 @@ +'); +} + +require_once '../Classes/PHPWord.php'; + +// New Word Document +echo date('H:i:s') , ' Create new PHPWord object' , EOL; +$PHPWord = new PHPWord(); + + +// Ads styles +$PHPWord->addParagraphStyle('pStyle', array('spacing'=>100)); +$PHPWord->addFontStyle('BoldText', array('bold'=>true)); +$PHPWord->addFontStyle('ColoredText', array('color'=>'FF8080')); +$PHPWord->addLinkStyle('NLink', array('color'=>'0000FF', 'underline'=>PHPWord_Style_Font::UNDERLINE_SINGLE)); + +// New portrait section +$section = $PHPWord->createSection(); + +// Add text run +$textrun = $section->createTextRun('pStyle'); + +$textrun->addText('Each textrun can contain native text, link elements or an image.'); +$textrun->addText(' No break is placed after adding an element.', 'BoldText'); +$textrun->addText(' Both '); +$textrun->addText('superscript', array('superScript' => true)); +$textrun->addText(' and '); +$textrun->addText('subscript', array('subScript' => true)); +$textrun->addText(' are also available.'); +$textrun->addText(' All elements are placed inside a paragraph with the optionally given p-Style.', 'ColoredText'); +$textrun->addText(' Sample Link: '); +$textrun->addLink('http://www.google.com', null, 'NLink'); +$textrun->addText(' Sample Image: '); +$textrun->addImage('old/_earth.jpg', array('width'=>18, 'height'=>18)); +$textrun->addText(' Here is some more text. '); + +// Save File +echo date('H:i:s') , ' Write to Word2007 format' , EOL; +$objWriter = PHPWord_IOFactory::createWriter($PHPWord, 'Word2007'); +$objWriter->save(str_replace('.php', '.docx', __FILE__)); + +/* Text Run is not currently supported for ODText +echo date('H:i:s') , ' Write to OpenDocumentText format' , EOL; +$objWriter = PHPWord_IOFactory::createWriter($PHPWord, 'ODText'); +$objWriter->save(str_replace('.php', '.odt', __FILE__)); +*/ + +/* Text Run is not currently supported for RTF +echo date('H:i:s') , ' Write to RTF format' , EOL; +$objWriter = PHPWord_IOFactory::createWriter($PHPWord, 'RTF'); +$objWriter->save(str_replace('.php', '.rtf', __FILE__)); +*/ + +// Echo memory peak usage +echo date('H:i:s') , ' Peak memory usage: ' , (memory_get_peak_usage(true) / 1024 / 1024) , ' MB' , EOL; + +// Echo done +echo date('H:i:s') , ' Done writing file' , EOL; \ No newline at end of file diff --git a/samples/Sample_05_Multicolumn.php b/samples/Sample_05_Multicolumn.php new file mode 100644 index 0000000000..a7889a855e --- /dev/null +++ b/samples/Sample_05_Multicolumn.php @@ -0,0 +1,66 @@ +'); +} + +require_once '../Classes/PHPWord.php'; + +// New Word Document +echo date('H:i:s') , " Create new PHPWord object" , EOL; +$PHPWord = new PHPWord(); +$filler = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. ' . + 'Nulla fermentum, tortor id adipiscing adipiscing, tortor turpis commodo. ' . + 'Donec vulputate iaculis metus, vel luctus dolor hendrerit ac. ' . + 'Suspendisse congue congue leo sed pellentesque.'; + +// Normal +$section = $PHPWord->createSection(); +$section->addText('Normal paragraph. ' . $filler); + +// Two columns +$section = $PHPWord->createSection(array( + 'colsNum' => 2, + 'colsSpace' => 1440, + 'breakType' => 'continuous')); +$section->addText('Three columns, one inch (1440 twips) spacing. ' . $filler); + +// Normal +$section = $PHPWord->createSection(array('breakType' => 'continuous')); +$section->addText('Normal paragraph again. ' . $filler); + +// Three columns +$section = $PHPWord->createSection(array( + 'colsNum' => 3, + 'colsSpace' => 720, + 'breakType' => 'continuous')); +$section->addText('Three columns, half inch (720 twips) spacing. ' . $filler); + +// Normal +$section = $PHPWord->createSection(array('breakType' => 'continuous')); +$section->addText('Normal paragraph again.'); + +// Save File +echo date('H:i:s') , " Write to Word2007 format" , EOL; +$objWriter = PHPWord_IOFactory::createWriter($PHPWord, 'Word2007'); +$objWriter->save(str_replace('.php', '.docx', __FILE__)); + +// echo date('H:i:s') , " Write to OpenDocumentText format" , EOL; +// $objWriter = PHPWord_IOFactory::createWriter($PHPWord, 'ODText'); +// $objWriter->save(str_replace('.php', '.odt', __FILE__)); + +// echo date('H:i:s') , " Write to RTF format" , EOL; +// $objWriter = PHPWord_IOFactory::createWriter($PHPWord, 'RTF'); +// $objWriter->save(str_replace('.php', '.rtf', __FILE__)); + + +// Echo memory peak usage +echo date('H:i:s') , " Peak memory usage: " , (memory_get_peak_usage(true) / 1024 / 1024) , " MB" , EOL; + +// Echo done +echo date('H:i:s') , " Done writing file" , EOL; diff --git a/samples/Sample_06_Footnote.php b/samples/Sample_06_Footnote.php new file mode 100755 index 0000000000..123dedccdf --- /dev/null +++ b/samples/Sample_06_Footnote.php @@ -0,0 +1,54 @@ +'); +} +require_once '../Classes/PHPWord.php'; + +// New Word Document +echo date('H:i:s') , " Create new PHPWord object" , EOL; +$PHPWord = new PHPWord(); + +// New portrait section +$section = $PHPWord->createSection(); + +// Add style definitions +$PHPWord->addParagraphStyle('pStyle', array('spacing'=>100)); +$PHPWord->addFontStyle('BoldText', array('bold'=>true)); +$PHPWord->addFontStyle('ColoredText', array('color'=>'FF8080')); +$PHPWord->addLinkStyle('NLink', array('color'=>'0000FF', 'underline'=>PHPWord_Style_Font::UNDERLINE_SINGLE)); + +// Add text elements +$textrun = $section->createTextRun('pStyle'); +$textrun->addText('This is some lead text in a paragraph with a following footnote. ','pStyle'); + +$footnote = $textrun->createFootnote(); +$footnote->addText('Just like a textrun a footnote can contain native text and link elements.'); +$footnote->addText(' No break is placed after adding an element.', 'BoldText'); +$footnote->addText(' All elements are placed inside a paragraph.', 'ColoredText'); +$footnote->addText(' The best search engine: '); +$footnote->addLink('http://www.google.com', null, 'NLink'); +$footnote->addText('. Also not bad: '); +$footnote->addLink('http://www.bing.com', null, 'NLink'); + +$textrun->addText('The trailing text in the paragraph.'); + +$section->addText('You can also create the footnote directly from the section making it wrap in a paragraph like the footnote below this paragraph. But is is best used from within a textrun.'); +$footnote = $section->createFootnote(); +$footnote->addText('The reference for this is wrapped in its own line'); + +// Save File +echo date('H:i:s') , " Write to Word2007 format" , EOL; +$objWriter = PHPWord_IOFactory::createWriter($PHPWord, 'Word2007'); +$objWriter->save(str_replace('.php', '.docx', __FILE__)); + + +// Echo memory peak usage +echo date('H:i:s') , " Peak memory usage: " , (memory_get_peak_usage(true) / 1024 / 1024) , " MB" , EOL; + +// Echo done +echo date('H:i:s') , " Done writing file" , EOL; diff --git a/samples/Sample_07_TemplateCloneRow.docx b/samples/Sample_07_TemplateCloneRow.docx new file mode 100755 index 0000000000..25a8c418b6 Binary files /dev/null and b/samples/Sample_07_TemplateCloneRow.docx differ diff --git a/samples/Sample_07_TemplateCloneRow.php b/samples/Sample_07_TemplateCloneRow.php new file mode 100755 index 0000000000..ccdee2c32d --- /dev/null +++ b/samples/Sample_07_TemplateCloneRow.php @@ -0,0 +1,54 @@ +loadTemplate('Sample_07_TemplateCloneRow.docx'); + +// Simple table +$document->cloneRow('rowValue', 10); + +$document->setValue('rowValue#1', 'Sun'); +$document->setValue('rowValue#2', 'Mercury'); +$document->setValue('rowValue#3', 'Venus'); +$document->setValue('rowValue#4', 'Earth'); +$document->setValue('rowValue#5', 'Mars'); +$document->setValue('rowValue#6', 'Jupiter'); +$document->setValue('rowValue#7', 'Saturn'); +$document->setValue('rowValue#8', 'Uranus'); +$document->setValue('rowValue#9', 'Neptun'); +$document->setValue('rowValue#10', 'Pluto'); + +$document->setValue('rowNumber#1', '1'); +$document->setValue('rowNumber#2', '2'); +$document->setValue('rowNumber#3', '3'); +$document->setValue('rowNumber#4', '4'); +$document->setValue('rowNumber#5', '5'); +$document->setValue('rowNumber#6', '6'); +$document->setValue('rowNumber#7', '7'); +$document->setValue('rowNumber#8', '8'); +$document->setValue('rowNumber#9', '9'); +$document->setValue('rowNumber#10', '10'); + +$document->setValue('weekday', date('l')); +$document->setValue('time', date('H:i')); + +// Table with a spanned cell +$document->cloneRow('userId', 3); + +$document->setValue('userId#1', '1'); +$document->setValue('userFirstName#1', 'James'); +$document->setValue('userName#1', 'Taylor'); +$document->setValue('userPhone#1', '+1 428 889 773'); + +$document->setValue('userId#2', '2'); +$document->setValue('userFirstName#2', 'Robert'); +$document->setValue('userName#2', 'Bell'); +$document->setValue('userPhone#2', '+1 428 889 774'); + +$document->setValue('userId#3', '3'); +$document->setValue('userFirstName#3', 'Michael'); +$document->setValue('userName#3', 'Ray'); +$document->setValue('userPhone#3', '+1 428 889 775'); + +$document->saveAs('Sample_07_TemplateCloneRow_result.docx'); diff --git a/samples/Sample_08_ParagraphPagination.php b/samples/Sample_08_ParagraphPagination.php new file mode 100644 index 0000000000..97b43032f1 --- /dev/null +++ b/samples/Sample_08_ParagraphPagination.php @@ -0,0 +1,76 @@ +'); +} + +require_once '../Classes/PHPWord.php'; + +// New Word document +echo date('H:i:s') , " Create new PHPWord object" , EOL; +$PHPWord = new PHPWord(); +$PHPWord->setDefaultParagraphStyle(array( + 'align' => 'both', + 'spaceAfter' => PHPWord_Shared_Font::pointSizeToTwips(12), + 'spacing' => 120, +)); + +// Sample +$section = $PHPWord->createSection(); + +$section->addText('Below are the samples on how to control your paragraph ' . + 'pagination. See "Line and Page Break" tab on paragraph properties ' . + 'window to see the attribute set by these controls.', + array('bold' => true), null); + +$section->addText('Paragraph with widowControl = false (default: true). ' . + 'A "widow" is the last line of a paragraph printed by itself at the top ' . + 'of a page. An "orphan" is the first line of a paragraph printed by ' . + 'itself at the bottom of a page. Set this option to "false" if you want ' . + 'to disable this automatic control.', + null, array('widowControl' => false)); + +$section->addText('Paragraph with keepNext = true (default: false). ' . + '"Keep with next" is used to prevent Word from inserting automatic page ' . + 'breaks between paragraphs. Set this option to "true" if you do not want ' . + 'your paragraph to be separated with the next paragraph.', + null, array('keepNext' => true)); + +$section->addText('Paragraph with keepLines = true (default: false). ' . + '"Keep lines together" will prevent Word from inserting an automatic page ' . + 'break within a paragraph. Set this option to "true" if you do not want ' . + 'all lines of your paragraph to be in the same page.', + null, array('keepLines' => true)); + +$section->addText('Keep scrolling. More below.'); + +$section->addText('Paragraph with pageBreakBefore = true (default: false). ' . + 'Different with all other control above, "page break before" separates ' . + 'your paragraph into the next page. This option is most useful for ' . + 'heading styles.', + null, array('pageBreakBefore' => true)); + +// Save File +echo date('H:i:s') , " Write to Word2007 format" , EOL; +$objWriter = PHPWord_IOFactory::createWriter($PHPWord, 'Word2007'); +$objWriter->save(str_replace('.php', '.docx', __FILE__)); + +// echo date('H:i:s') , " Write to OpenDocumentText format" , EOL; +// $objWriter = PHPWord_IOFactory::createWriter($PHPWord, 'ODText'); +// $objWriter->save(str_replace('.php', '.odt', __FILE__)); + +// echo date('H:i:s') , " Write to RTF format" , EOL; +// $objWriter = PHPWord_IOFactory::createWriter($PHPWord, 'RTF'); +// $objWriter->save(str_replace('.php', '.rtf', __FILE__)); + + +// Echo memory peak usage +echo date('H:i:s') , " Peak memory usage: " , (memory_get_peak_usage(true) / 1024 / 1024) , " MB" , EOL; + +// Echo done +echo date('H:i:s') , " Done writing file" , EOL;