diff --git a/.travis.yml b/.travis.yml index ad3df613..cf69291f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -25,14 +25,14 @@ before_script: - pyrus install pear/PHP_CodeSniffer - phpenv rehash ## PHP Copy/Paste Detector - #- curl -o phpcpd.phar https://phar.phpunit.de/phpcpd.phar + - curl -o phpcpd.phar https://phar.phpunit.de/phpcpd.phar ## PHP Mess Detector - #- pear config-set preferred_state beta - #- printf "\n" | pecl install imagick - #- pear channel-discover pear.phpmd.org - #- pear channel-discover pear.pdepend.org - #- pear install --alldeps phpmd/PHP_PMD - #- phpenv rehash + - pear config-set preferred_state beta + - printf "\n" | pecl install imagick + - pear channel-discover pear.phpmd.org + - pear channel-discover pear.pdepend.org + - pear install --alldeps phpmd/PHP_PMD + - phpenv rehash ## PHPLOC #- curl -o phploc.phar https://phar.phpunit.de/phploc.phar @@ -41,9 +41,9 @@ script: - phpcs --standard=PSR2 -n src/ --ignore=src/PhpWord/Shared/PCLZip - phpcs --standard=PSR2 -n tests/ ## PHP Copy/Paste Detector - #- php phpcpd.phar --verbose src/ + - php phpcpd.phar --verbose src/ ## PHP Mess Detector - #- phpmd src/ text unusedcode,naming,design + - phpmd src/ text phpmd.xml --exclude pclzip.lib.php ## PHPLOC #- php phploc.phar src/ ## PHPUnit diff --git a/CHANGELOG.md b/CHANGELOG.md index e23edf91..ccdac7ee 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,7 +26,7 @@ This release marked heavy refactorings on internal code structure with the creat - Link: Ability to add link in header/footer - @ivanlanin GH-187 - Object: Ability to add object in header, footer, textrun, and footnote - @ivanlanin GH-187 - Media: Add `Media::resetElements()` to reset all media data - @juzi GH-19 -- General: Add `Style::resetStyles()`, `Footnote::resetElements()`, and `TOC::resetTitles()` - @ivanlanin GH-187 +- General: Add `Style::resetStyles()` - @ivanlanin GH-187 - DOCX Reader: Ability to read header, footer, footnotes, link, preservetext, textbreak, pagebreak, table, list, image, and title - @ivanlanin - Endnote: Ability to add endnotes - @ivanlanin - ListItem: Ability to create custom list and reset list number - @ivanlanin GH-10 GH-198 @@ -66,6 +66,7 @@ This release marked heavy refactorings on internal code structure with the creat - `Element\Link::getLinkSrc` replaced by `Element\Link::getTarget` - `Element\Link::getLinkName` replaced by `Element\Link::getText` - `Style\Cell::getDefaultBorderColor` +- Static classes `Footnotes`, `Endnotes`, and `TOC` ### Miscellaneous @@ -87,6 +88,8 @@ This release marked heavy refactorings on internal code structure with the creat - Refactor: Apply composite pattern for writers - @ivanlanin - Refactor: Split `AbstractContainer` from `AbstractElement` - @ivanlanin - Refactor: Apply composite pattern for Word2007 reader - @ivanlanin +- Refactor: Replace static classes `Footnotes`, `Endnotes`, and `TOC` with `Collections` - @ivanlanin GH-206 +- QA: Reactivate `phpcpd` and `phpmd` on Travis - @ivanlanin ## 0.9.1 - 27 Mar 2014 diff --git a/samples/resources/Sample_11_ReadWord2007.docx b/samples/resources/Sample_11_ReadWord2007.docx index 2143c628..aefe9f48 100644 Binary files a/samples/resources/Sample_11_ReadWord2007.docx and b/samples/resources/Sample_11_ReadWord2007.docx differ diff --git a/src/PhpWord/Collection/AbstractCollection.php b/src/PhpWord/Collection/AbstractCollection.php new file mode 100644 index 00000000..7b5d4579 --- /dev/null +++ b/src/PhpWord/Collection/AbstractCollection.php @@ -0,0 +1,87 @@ +items; + } + + /** + * Get item by index + * + * @param int $index + * @return mixed + */ + public function getItem($index) + { + if (array_key_exists($index, $this->items)) { + return $this->items[$index]; + } else { + return null; + } + } + + /** + * Set item + * + * @param int $index + * @param mixed $item + */ + public function setItem($index, $item) + { + if (array_key_exists($index, $this->items)) { + $this->items[$index] = $item; + } + } + + /** + * Add new item + * + * @param mixed $item + * @return int + */ + public function addItem($item) + { + $index = $this->countItems() + 1; + $this->items[$index] = $item; + + return $index; + } + + /** + * Get item count + * + * @return int + */ + public function countItems() + { + return count($this->items); + } +} diff --git a/src/PhpWord/Collection/Endnotes.php b/src/PhpWord/Collection/Endnotes.php new file mode 100644 index 00000000..36c547a3 --- /dev/null +++ b/src/PhpWord/Collection/Endnotes.php @@ -0,0 +1,19 @@ +setElementIndex($this->countElements() + 1); $element->setElementId(); + $element->setPhpWord($this->phpWord); $this->elements[] = $element; } @@ -67,18 +74,17 @@ abstract class AbstractContainer extends AbstractElement * @param string $text * @param mixed $fontStyle * @param mixed $paragraphStyle - * @return Text + * @return \PhpOffice\PhpWord\Element\Text */ public function addText($text, $fontStyle = null, $paragraphStyle = null) { - $this->checkValidity('text'); + $this->checkValidity('Text'); // Reset paragraph style for footnote and textrun. They have their own if (in_array($this->container, array('textrun', 'footnote', 'endnote'))) { $paragraphStyle = null; } - $text = String::toUTF8($text); $textObject = new Text($text, $fontStyle, $paragraphStyle); $textObject->setDocPart($this->getDocPart(), $this->getDocPartId()); $this->addElement($textObject); @@ -90,11 +96,11 @@ abstract class AbstractContainer extends AbstractElement * Add textrun element * * @param mixed $paragraphStyle - * @return TextRun + * @return \PhpOffice\PhpWord\Element\TextRun */ public function addTextRun($paragraphStyle = null) { - $this->checkValidity('textrun'); + $this->checkValidity('Textrun'); $textRun = new TextRun($paragraphStyle); $textRun->setDocPart($this->getDocPart(), $this->getDocPartId()); @@ -106,70 +112,39 @@ abstract class AbstractContainer extends AbstractElement /** * Add link element * - * @param string $linkSrc - * @param string $linkName + * @param string $target + * @param string $text * @param mixed $fontStyle * @param mixed $paragraphStyle - * @return Link + * @return \PhpOffice\PhpWord\Element\Link */ - public function addLink($linkSrc, $linkName = null, $fontStyle = null, $paragraphStyle = null) + public function addLink($target, $text = null, $fontStyle = null, $paragraphStyle = null) { - $this->checkValidity('link'); + $this->checkValidity('Link'); $elementDocPart = $this->checkElementDocPart(); - $link = new Link(String::toUTF8($linkSrc), String::toUTF8($linkName), $fontStyle, $paragraphStyle); + $link = new Link($target, $text, $fontStyle, $paragraphStyle); $link->setDocPart($this->getDocPart(), $this->getDocPartId()); - $rId = Media::addElement($elementDocPart, 'link', $linkSrc); + $rId = Media::addElement($elementDocPart, 'link', $target); $link->setRelationId($rId); $this->addElement($link); return $link; } - /** - * Add a Title Element - * - * @param string $text - * @param int $depth - * @return Title - * @todo Enable title element in other containers - */ - public function addTitle($text, $depth = 1) - { - $this->checkValidity('title'); - - $styles = Style::getStyles(); - if (array_key_exists('Heading_' . $depth, $styles)) { - $style = 'Heading' . $depth; - } else { - $style = null; - } - $text = String::toUTF8($text); - $title = new Title($text, $depth, $style); - $title->setDocPart($this->getDocPart(), $this->getDocPartId()); - $data = Titles::addTitle($text, $depth); - $anchor = $data[0]; - $bookmarkId = $data[1]; - $title->setAnchor($anchor); - $title->setBookmarkId($bookmarkId); - $this->addElement($title); - - return $title; - } - /** * Add preserve text element * * @param string $text * @param mixed $fontStyle * @param mixed $paragraphStyle - * @return PreserveText + * @return \PhpOffice\PhpWord\Element\PreserveText */ public function addPreserveText($text, $fontStyle = null, $paragraphStyle = null) { - $this->checkValidity('preservetext'); + $this->checkValidity('PreserveText'); - $preserveText = new PreserveText(String::toUTF8($text), $fontStyle, $paragraphStyle); + $preserveText = new PreserveText($text, $fontStyle, $paragraphStyle); $preserveText->setDocPart($this->getDocPart(), $this->getDocPartId()); $this->addElement($preserveText); @@ -185,7 +160,7 @@ abstract class AbstractContainer extends AbstractElement */ public function addTextBreak($count = 1, $fontStyle = null, $paragraphStyle = null) { - $this->checkValidity('textbreak'); + $this->checkValidity('TextBreak'); for ($i = 1; $i <= $count; $i++) { $textBreak = new TextBreak($fontStyle, $paragraphStyle); @@ -200,48 +175,32 @@ abstract class AbstractContainer extends AbstractElement * @param string $text * @param int $depth * @param mixed $fontStyle - * @param mixed $styleList + * @param mixed $listStyle * @param mixed $paragraphStyle - * @return ListItem + * @return \PhpOffice\PhpWord\Element\ListItem */ - public function addListItem($text, $depth = 0, $fontStyle = null, $styleList = null, $paragraphStyle = null) + public function addListItem($text, $depth = 0, $fontStyle = null, $listStyle = null, $paragraphStyle = null) { - $this->checkValidity('listitem'); + $this->checkValidity('ListItem'); - $listItem = new ListItem(String::toUTF8($text), $depth, $fontStyle, $styleList, $paragraphStyle); + $listItem = new ListItem($text, $depth, $fontStyle, $listStyle, $paragraphStyle); $listItem->setDocPart($this->getDocPart(), $this->getDocPartId()); $this->addElement($listItem); return $listItem; } - /** - * Add table element - * - * @param mixed $style - * @return Table - */ - public function addTable($style = null) - { - $this->checkValidity('table'); - - $table = new Table($this->getDocPart(), $this->getDocPartId(), $style); - $this->addElement($table); - - return $table; - } - /** * Add image element * * @param string $src * @param mixed $style Image style * @param boolean $isWatermark - * @return Image + * @return \PhpOffice\PhpWord\Element\Image */ public function addImage($src, $style = null, $isWatermark = false) { - $this->checkValidity('image'); + $this->checkValidity('Image'); $elementDocPart = $this->checkElementDocPart(); $image = new Image($src, $style, $isWatermark); @@ -260,13 +219,12 @@ abstract class AbstractContainer extends AbstractElement * * @param string $src * @param mixed $style - * @return Object + * @return \PhpOffice\PhpWord\Element\Object * @throws \PhpOffice\PhpWord\Exception\Exception - * @todo Enable OLE object element in header and footer */ public function addObject($src, $style = null) { - $this->checkValidity('object'); + $this->checkValidity('Object'); $elementDocPart = $this->checkElementDocPart(); $object = new Object($src, $style); @@ -294,40 +252,36 @@ abstract class AbstractContainer extends AbstractElement * Add footnote element * * @param mixed $paragraphStyle - * @return Footnote + * @param string $elementName + * @return \PhpOffice\PhpWord\Element\Footnote */ - public function addFootnote($paragraphStyle = null) + public function addFootnote($paragraphStyle = null, $elementName = 'Footnote') { - $this->checkValidity('footnote'); + $this->checkValidity($elementName); + $docPart = strtolower($elementName); + $addMethod = "add{$elementName}"; + $elementClass = 'PhpOffice\\PhpWord\\Element\\' . $elementName; - $footnote = new Footnote($paragraphStyle); - $rId = Footnotes::addElement($footnote); + $note = new $elementClass($paragraphStyle); + // if ($this->phpWord instanceof PhpWord) { + $rId = $this->phpWord->$addMethod($note); + // } + $note->setDocPart($docPart, $this->getDocPartId()); + $note->setRelationId($rId); + $this->addElement($note); - $footnote->setDocPart('footnote', $this->getDocPartId()); - $footnote->setRelationId($rId); - $this->addElement($footnote); - - return $footnote; + return $note; } /** * Add endnote element * * @param mixed $paragraphStyle - * @return Endnote + * @return \PhpOffice\PhpWord\Element\Endnote */ public function addEndnote($paragraphStyle = null) { - $this->checkValidity('endnote'); - - $endnote = new Endnote($paragraphStyle); - $rId = Endnotes::addElement($endnote); - - $endnote->setDocPart('endnote', $this->getDocPartId()); - $endnote->setRelationId($rId); - $this->addElement($endnote); - - return $endnote; + return $this->addFootnote($paragraphStyle, 'Endnote'); } /** @@ -337,13 +291,13 @@ abstract class AbstractContainer extends AbstractElement * @param string $text * @param mixed $fontStyle * @param mixed $paragraphStyle - * @return CheckBox + * @return \PhpOffice\PhpWord\Element\CheckBox */ public function addCheckBox($name, $text, $fontStyle = null, $paragraphStyle = null) { - $this->checkValidity('checkbox'); + $this->checkValidity('CheckBox'); - $checkBox = new CheckBox(String::toUTF8($name), String::toUTF8($text), $fontStyle, $paragraphStyle); + $checkBox = new CheckBox($name, $text, $fontStyle, $paragraphStyle); $checkBox->setDocPart($this->getDocPart(), $this->getDocPartId()); $this->addElement($checkBox); @@ -361,26 +315,24 @@ abstract class AbstractContainer extends AbstractElement // Valid containers for each element $allContainers = array('section', 'header', 'footer', 'cell', 'textrun', 'footnote', 'endnote'); $validContainers = array( - 'text' => $allContainers, - 'link' => $allContainers, - 'textbreak' => $allContainers, - 'image' => $allContainers, - 'object' => $allContainers, - 'textrun' => array('section', 'header', 'footer', 'cell'), - 'listitem' => array('section', 'header', 'footer', 'cell'), - 'checkbox' => array('section', 'header', 'footer', 'cell'), - 'table' => array('section', 'header', 'footer'), - 'footnote' => array('section', 'textrun', 'cell'), - 'endnote' => array('section', 'textrun', 'cell'), - 'preservetext' => array('header', 'footer', 'cell'), - 'title' => array('section'), + 'Text' => $allContainers, + 'Link' => $allContainers, + 'TextBreak' => $allContainers, + 'Image' => $allContainers, + 'Object' => $allContainers, + 'TextRun' => array('section', 'header', 'footer', 'cell'), + 'ListItem' => array('section', 'header', 'footer', 'cell'), + 'CheckBox' => array('section', 'header', 'footer', 'cell'), + 'Footnote' => array('section', 'textrun', 'cell'), + 'Endnote' => array('section', 'textrun', 'cell'), + 'PreserveText' => array('header', 'footer', 'cell'), ); // Special condition, e.g. preservetext can only exists in cell when // the cell is located in header or footer $validSubcontainers = array( - 'preservetext' => array(array('cell'), array('header', 'footer')), - 'footnote' => array(array('cell', 'textrun'), array('section')), - 'endnote' => array(array('cell', 'textrun'), array('section')), + 'PreserveText' => array(array('cell'), array('header', 'footer')), + 'Footnote' => array(array('cell', 'textrun'), array('section')), + 'Endnote' => array(array('cell', 'textrun'), array('section')), ); // Check if a method is valid for current container diff --git a/src/PhpWord/Element/AbstractElement.php b/src/PhpWord/Element/AbstractElement.php index 6e993748..fdad7daf 100644 --- a/src/PhpWord/Element/AbstractElement.php +++ b/src/PhpWord/Element/AbstractElement.php @@ -9,6 +9,7 @@ namespace PhpOffice\PhpWord\Element; +use PhpOffice\PhpWord\PhpWord; use PhpOffice\PhpWord\Style; /** @@ -18,6 +19,11 @@ use PhpOffice\PhpWord\Style; */ abstract class AbstractElement { + /** + * PhpWord object + */ + protected $phpWord; + /** * Container type section|header|footer|cell|textrun|footnote|endnote * @@ -75,6 +81,26 @@ abstract class AbstractElement */ protected $relationId; + /** + * Get PhpWord + * + * @return \PhpOffice\PhpWord\PhpWord + */ + public function getPhpWord() + { + return $this->phpWord; + } + + /** + * Set PhpWord + * + * @param \PhpOffice\PhpWord\PhpWord + */ + public function setPhpWord(PhpWord &$phpWord = null) + { + $this->phpWord = $phpWord; + } + /** * Get section number * diff --git a/src/PhpWord/Element/CheckBox.php b/src/PhpWord/Element/CheckBox.php index f273c128..6353e2d4 100644 --- a/src/PhpWord/Element/CheckBox.php +++ b/src/PhpWord/Element/CheckBox.php @@ -9,6 +9,8 @@ namespace PhpOffice\PhpWord\Element; +use PhpOffice\PhpWord\Shared\String; + /** * Check box element */ @@ -44,7 +46,7 @@ class CheckBox extends Text */ public function setName($name) { - $this->name = $name; + $this->name = String::toUTF8($name); return $this; } diff --git a/src/PhpWord/Element/Footer.php b/src/PhpWord/Element/Footer.php index 50ec8236..9090720d 100644 --- a/src/PhpWord/Element/Footer.php +++ b/src/PhpWord/Element/Footer.php @@ -9,21 +9,36 @@ namespace PhpOffice\PhpWord\Element; +use PhpOffice\PhpWord\Element\Table; + /** * Footer element */ class Footer extends AbstractContainer { + /** + * Header/footer types constants + * + * @var string + * @link http://www.schemacentral.com/sc/ooxml/a-wtype-4.html Header or Footer Type + */ const AUTO = 'default'; // default and odd pages const FIRST = 'first'; const EVEN = 'even'; + /** + * Container type + * + * @var string + */ + protected $container = 'footer'; + /** * Header type * * @var string */ - private $type = self::AUTO; + protected $type = self::AUTO; /** * Create new instance @@ -32,12 +47,11 @@ class Footer extends AbstractContainer * @param int $footerId * @param string $type */ - public function __construct($sectionId, $footerId = 1, $type = self::AUTO) + public function __construct($sectionId, $containerId = 1, $type = self::AUTO) { - $this->container = 'footer'; $this->sectionId = $sectionId; $this->setType($type); - $this->setDocPart($this->container, ($sectionId - 1) * 3 + $footerId); + $this->setDocPart($this->container, ($sectionId - 1) * 3 + $containerId); } /** @@ -48,6 +62,9 @@ class Footer extends AbstractContainer */ public function setType($value = self::AUTO) { + if (!in_array($value, array(self::AUTO, self::FIRST, self::EVEN))) { + $value = self::AUTO; + } $this->type = $value; } @@ -61,4 +78,49 @@ class Footer extends AbstractContainer { return $this->type; } + + /** + * Reset type to default + * + * @return string + */ + public function resetType() + { + return $this->type = self::AUTO; + } + + /** + * First page only header + * + * @return string + */ + public function firstPage() + { + return $this->type = self::FIRST; + } + + /** + * Even numbered pages only + * + * @return string + */ + public function evenPage() + { + return $this->type = self::EVEN; + } + + /** + * Add table element + * + * @param mixed $style + * @return \PhpOffice\PhpWord\Element\Table + * @todo Merge with the same function on Section + */ + public function addTable($style = null) + { + $table = new Table($this->getDocPart(), $this->getDocPartId(), $style); + $this->addElement($table); + + return $table; + } } diff --git a/src/PhpWord/Element/Header.php b/src/PhpWord/Element/Header.php index 2c963d84..774e63f9 100644 --- a/src/PhpWord/Element/Header.php +++ b/src/PhpWord/Element/Header.php @@ -14,39 +14,15 @@ use PhpOffice\PhpWord\Element\Image; /** * Header element */ -class Header extends AbstractContainer +class Header extends Footer { - /** - * Header types constants - * - * @var string - * @link http://www.schemacentral.com/sc/ooxml/a-wtype-4.html Header or Footer Type - */ - const AUTO = 'default'; // default and odd pages - const FIRST = 'first'; - const EVEN = 'even'; /** - * Header type + * Container type * * @var string */ - private $type = self::AUTO; - - /** - * Create new instance - * - * @param int $sectionId - * @param int $headerId - * @param string $type - */ - public function __construct($sectionId, $headerId = 1, $type = self::AUTO) - { - $this->container = 'header'; - $this->sectionId = $sectionId; - $this->setType($type); - $this->setDocPart($this->container, ($sectionId - 1) * 3 + $headerId); - } + protected $container = 'header'; /** * Add a Watermark Element @@ -59,58 +35,4 @@ class Header extends AbstractContainer { return $this->addImage($src, $style, true); } - - /** - * Set header type - * - * @param string $value - * @since 0.10.0 - */ - public function setType($value = self::AUTO) - { - if (!in_array($value, array(self::AUTO, self::FIRST, self::EVEN))) { - $value = self::AUTO; - } - $this->type = $value; - } - - /** - * Get header type - * - * @return string - */ - public function getType() - { - return $this->type; - } - - /** - * Reset type to default - * - * @return string - */ - public function resetType() - { - return $this->type = self::AUTO; - } - - /** - * First page only header - * - * @return string - */ - public function firstPage() - { - return $this->type = self::FIRST; - } - - /** - * Even numbered pages only - * - * @return string - */ - public function evenPage() - { - return $this->type = self::EVEN; - } } diff --git a/src/PhpWord/Element/Link.php b/src/PhpWord/Element/Link.php index 31b06c68..e4ead5d5 100644 --- a/src/PhpWord/Element/Link.php +++ b/src/PhpWord/Element/Link.php @@ -9,6 +9,7 @@ namespace PhpOffice\PhpWord\Element; +use PhpOffice\PhpWord\Shared\String; use PhpOffice\PhpWord\Style\Font; use PhpOffice\PhpWord\Style\Paragraph; @@ -56,8 +57,8 @@ class Link extends AbstractElement */ public function __construct($target, $text = null, $fontStyle = null, $paragraphStyle = null) { - $this->target = $target; - $this->text = is_null($text) ? $target : $text; + $this->target = String::toUTF8($target); + $this->text = is_null($text) ? $this->target : String::toUTF8($text); $this->fontStyle = $this->setStyle(new Font('text'), $fontStyle); $this->paragraphStyle = $this->setStyle(new Paragraph(), $paragraphStyle); diff --git a/src/PhpWord/Element/ListItem.php b/src/PhpWord/Element/ListItem.php index 66061537..e52d0252 100644 --- a/src/PhpWord/Element/ListItem.php +++ b/src/PhpWord/Element/ListItem.php @@ -9,6 +9,7 @@ namespace PhpOffice\PhpWord\Element; +use PhpOffice\PhpWord\Shared\String; use PhpOffice\PhpWord\Style\ListItem as ListItemStyle; /** @@ -49,7 +50,7 @@ class ListItem extends AbstractElement */ public function __construct($text, $depth = 0, $fontStyle = null, $listStyle = null, $paragraphStyle = null) { - $this->textObject = new Text($text, $fontStyle, $paragraphStyle); + $this->textObject = new Text(String::toUTF8($text), $fontStyle, $paragraphStyle); $this->depth = $depth; // Version >= 0.10.0 will pass numbering style name. Older version will use old method diff --git a/src/PhpWord/Element/PreserveText.php b/src/PhpWord/Element/PreserveText.php index ac7d1f52..bf280d66 100644 --- a/src/PhpWord/Element/PreserveText.php +++ b/src/PhpWord/Element/PreserveText.php @@ -9,6 +9,7 @@ namespace PhpOffice\PhpWord\Element; +use PhpOffice\PhpWord\Shared\String; use PhpOffice\PhpWord\Style\Font; use PhpOffice\PhpWord\Style\Paragraph; @@ -52,7 +53,8 @@ class PreserveText extends AbstractElement $this->fontStyle = $this->setStyle(new Font('text'), $fontStyle); $this->paragraphStyle = $this->setStyle(new Paragraph(), $paragraphStyle); - $matches = preg_split('/({.*?})/', $text, null, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY); + $this->text = String::toUTF8($text); + $matches = preg_split('/({.*?})/', $this->text, null, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY); if (isset($matches[0])) { $this->text = $matches; } diff --git a/src/PhpWord/Element/Row.php b/src/PhpWord/Element/Row.php index dc4b8a44..ed8e1141 100644 --- a/src/PhpWord/Element/Row.php +++ b/src/PhpWord/Element/Row.php @@ -63,6 +63,7 @@ class Row extends AbstractElement public function addCell($width = null, $style = null) { $cell = new Cell($this->getDocPart(), $this->getDocPartId(), $width, $style); + $cell->setPhpWord($this->phpWord); $this->cells[] = $cell; return $cell; } diff --git a/src/PhpWord/Element/Section.php b/src/PhpWord/Element/Section.php index 64e226ab..dd1c0afb 100644 --- a/src/PhpWord/Element/Section.php +++ b/src/PhpWord/Element/Section.php @@ -9,10 +9,12 @@ namespace PhpOffice\PhpWord\Element; +use PhpOffice\PhpWord\Element\PageBreak; +use PhpOffice\PhpWord\Element\Table; +use PhpOffice\PhpWord\Element\TOC; +use PhpOffice\PhpWord\Element\Title; use PhpOffice\PhpWord\Exception\Exception; use PhpOffice\PhpWord\Style\Section as SectionSettings; -use PhpOffice\PhpWord\Element\PageBreak; -use PhpOffice\PhpWord\Element\TOC; /** * Section @@ -82,12 +84,47 @@ class Section extends AbstractContainer return $this->settings; } + /** + * Add a Title Element + * + * @param string $text + * @param int $depth + * @return \PhpOffice\PhpWord\Element\Title + */ + public function addTitle($text, $depth = 1) + { + $title = new Title($text, $depth); + $title->setDocPart($this->getDocPart(), $this->getDocPartId()); + if ($this->phpWord instanceof PhpWord) { + $bookmarkId = $this->phpWord->addTitle($title); + $title->setBookmarkId($bookmarkId); + } + $this->addElement($title); + + return $title; + } + /** * Add a PageBreak Element */ public function addPageBreak() { - $this->elements[] = new PageBreak(); + $this->addElement(new PageBreak()); + } + + /** + * Add table element + * + * @param mixed $style + * @return \PhpOffice\PhpWord\Element\Table + * @todo Merge with the same function on Footer + */ + public function addTable($style = null) + { + $table = new Table($this->getDocPart(), $this->getDocPartId(), $style); + $this->addElement($table); + + return $table; } /** @@ -102,7 +139,8 @@ class Section extends AbstractContainer public function addTOC($fontStyle = null, $tocStyle = null, $minDepth = 1, $maxDepth = 9) { $toc = new TOC($fontStyle, $tocStyle, $minDepth, $maxDepth); - $this->elements[] = $toc; + $this->addElement($toc); + return $toc; } @@ -187,6 +225,8 @@ class Section extends AbstractContainer if (in_array($type, array(Header::AUTO, Header::FIRST, Header::EVEN))) { $index = count($collection); $container = new $containerClass($this->sectionId, ++$index, $type); + $container->setPhpWord($this->phpWord); + $collection[$index] = $container; return $container; } else { diff --git a/src/PhpWord/Element/TOC.php b/src/PhpWord/Element/TOC.php index ac48a49d..b8eee6e5 100644 --- a/src/PhpWord/Element/TOC.php +++ b/src/PhpWord/Element/TOC.php @@ -9,7 +9,7 @@ namespace PhpOffice\PhpWord\Element; -use PhpOffice\PhpWord\TOC as Titles; +use PhpOffice\PhpWord\PhpWord; use PhpOffice\PhpWord\Style\Font; use PhpOffice\PhpWord\Style\TOC as TOCStyle; @@ -87,16 +87,20 @@ class TOC extends AbstractElement */ public function getTitles() { - $titles = Titles::getTitles(); + if (!$this->phpWord instanceof PhpWord) { + return array(); + } + + $titles = $this->phpWord->getTitles()->getItems(); foreach ($titles as $i => $title) { - if ($this->minDepth > $title['depth']) { + $depth = $title->getDepth(); + if ($this->minDepth > $depth) { unset($titles[$i]); } - if (($this->maxDepth != 0) && ($this->maxDepth < $title['depth'])) { + if (($this->maxDepth != 0) && ($this->maxDepth < $depth)) { unset($titles[$i]); } } - $titles = array_merge(array(), $titles); return $titles; } diff --git a/src/PhpWord/Element/Table.php b/src/PhpWord/Element/Table.php index 1fa729e1..89bef829 100644 --- a/src/PhpWord/Element/Table.php +++ b/src/PhpWord/Element/Table.php @@ -60,6 +60,7 @@ class Table extends AbstractElement public function addRow($height = null, $style = null) { $row = new Row($this->getDocPart(), $this->getDocPartId(), $height, $style); + $row->setPhpWord($this->phpWord); $this->rows[] = $row; return $row; } diff --git a/src/PhpWord/Element/Text.php b/src/PhpWord/Element/Text.php index 96e0e164..481f532b 100644 --- a/src/PhpWord/Element/Text.php +++ b/src/PhpWord/Element/Text.php @@ -9,6 +9,7 @@ namespace PhpOffice\PhpWord\Element; +use PhpOffice\PhpWord\Shared\String; use PhpOffice\PhpWord\Style\Font; use PhpOffice\PhpWord\Style\Paragraph; @@ -127,7 +128,7 @@ class Text extends AbstractElement */ public function setText($text) { - $this->text = $text; + $this->text = String::toUTF8($text); return $this; } diff --git a/src/PhpWord/Element/Title.php b/src/PhpWord/Element/Title.php index 93b48d62..f6d3bba9 100644 --- a/src/PhpWord/Element/Title.php +++ b/src/PhpWord/Element/Title.php @@ -9,6 +9,9 @@ namespace PhpOffice\PhpWord\Element; +use PhpOffice\PhpWord\Style; +use PhpOffice\PhpWord\Shared\String; + /** * Title element */ @@ -40,10 +43,10 @@ class Title extends AbstractElement * * @var int */ - private $bookmarkId; + private $bookmarkId = 1; /** - * Title style + * Name of the heading style, e.g. 'Heading1' * * @var string */ @@ -55,40 +58,20 @@ class Title extends AbstractElement * * @param string $text * @param int $depth - * @param string $style Name of the heading style, e.g. 'Heading1' + * @param string $style */ - public function __construct($text, $depth = 1, $style = null) + public function __construct($text, $depth = 1) { - if (!is_null($style)) { - $this->style = $style; + + $this->text = String::toUTF8($text); + $this->depth = $depth; + if (array_key_exists('Heading_' . $this->depth, Style::getStyles())) { + $this->style = 'Heading' . $this->depth; } - $this->text = $text; - $this->depth = $depth; - return $this; } - /** - * Set Anchor - * - * @param int $anchor - */ - public function setAnchor($anchor) - { - $this->anchor = $anchor; - } - - /** - * Get Anchor - * - * @return int - */ - public function getAnchor() - { - return $this->anchor; - } - /** * Set Bookmark ID * @@ -138,4 +121,28 @@ class Title extends AbstractElement { return $this->style; } + + /** + * Set Anchor + * + * @param int $anchor + * @deprecated 0.10.0 + * @codeCoverageIgnore + */ + public function setAnchor($anchor) + { + $this->anchor = $anchor; + } + + /** + * Get Anchor + * + * @return int + * @deprecated 0.10.0 + * @codeCoverageIgnore + */ + public function getAnchor() + { + return '_Toc' . (252634154 + $this->bookmarkId); + } } diff --git a/src/PhpWord/Endnotes.php b/src/PhpWord/Endnotes.php deleted file mode 100644 index 6587dfe9..00000000 --- a/src/PhpWord/Endnotes.php +++ /dev/null @@ -1,95 +0,0 @@ -documentProperties = new DocumentProperties(); + $this->titles = new Titles(); + $this->footnotes = new Footnotes(); + $this->endnotes = new Endnotes(); $this->defaultFontName = self::DEFAULT_FONT_NAME; $this->defaultFontSize = self::DEFAULT_FONT_SIZE; } @@ -92,6 +119,16 @@ class PhpWord return $this; } + /** + * Get all sections + * + * @return \PhpOffice\PhpWord\Element\Section[] + */ + public function getSections() + { + return $this->sections; + } + /** * Create new section * @@ -101,11 +138,75 @@ class PhpWord public function addSection($settings = null) { $section = new Section(count($this->sections) + 1, $settings); + $section->setPhpWord($this); $this->sections[] = $section; return $section; } + /** + * Get titles + * + * @return \PhpOffice\PhpWord\Collection\Titles + */ + public function getTitles() + { + return $this->titles; + } + + /** + * Add new title + * + * @param \PhpOffice\PhpWord\Element\Title $title + * @return int + */ + public function addTitle($title) + { + return $this->titles->addItem($title); + } + + /** + * Get footnotes + * + * @return \PhpOffice\PhpWord\Collection\Footnotes + */ + public function getFootnotes() + { + return $this->footnotes; + } + + /** + * Add new footnote + * + * @param \PhpOffice\PhpWord\Element\Footnote $footnote + * @return int + */ + public function addFootnote($footnote) + { + return $this->footnotes->addItem($footnote); + } + + /** + * Get endnotes + * + * @return \PhpOffice\PhpWord\Collection\Endnotes + */ + public function getEndnotes() + { + return $this->endnotes; + } + + /** + * Add new endnote + * + * @param \PhpOffice\PhpWord\Element\Endnote $endnote + * @return int + */ + public function addEndnote($endnote) + { + return $this->endnotes->addItem($endnote); + } + /** * Get default font name * @@ -225,16 +326,6 @@ class PhpWord Style::addNumberingStyle($styleName, $styles); } - /** - * Get all sections - * - * @return \PhpOffice\PhpWord\Element\Section[] - */ - public function getSections() - { - return $this->sections; - } - /** * Load template by filename * diff --git a/src/PhpWord/Reader/Word2007/DocProps.php b/src/PhpWord/Reader/Word2007/DocProps.php deleted file mode 100644 index 2c76417a..00000000 --- a/src/PhpWord/Reader/Word2007/DocProps.php +++ /dev/null @@ -1,63 +0,0 @@ -getDomFromZip($this->docFile, $this->xmlFile); - - $docProps = $phpWord->getDocumentProperties(); - - $nodes = $xmlReader->getElements('*'); - if ($nodes->length > 0) { - foreach ($nodes as $node) { - if (!array_key_exists($node->nodeName, $this->mapping)) { - continue; - } - $method = $this->mapping[$node->nodeName]; - $value = $node->nodeValue == '' ? null : $node->nodeValue; - if (array_key_exists($node->nodeName, $this->callbacks)) { - $value = $this->callbacks[$node->nodeName]($value); - } - if (method_exists($docProps, $method)) { - $docProps->$method($value); - } - } - } - } -} diff --git a/src/PhpWord/Reader/Word2007/DocPropsApp.php b/src/PhpWord/Reader/Word2007/DocPropsApp.php index 7797528a..40d08667 100644 --- a/src/PhpWord/Reader/Word2007/DocPropsApp.php +++ b/src/PhpWord/Reader/Word2007/DocPropsApp.php @@ -12,7 +12,7 @@ namespace PhpOffice\PhpWord\Reader\Word2007; /** * Extended properties reader */ -class DocPropsApp extends DocProps +class DocPropsApp extends DocPropsCore { /** * Property mapping @@ -20,4 +20,11 @@ class DocPropsApp extends DocProps * @var array */ protected $mapping = array('Company' => 'setCompany', 'Manager' => 'setManager'); + + /** + * Callback functions + * + * @var array + */ + protected $callbacks = array(); } diff --git a/src/PhpWord/Reader/Word2007/DocPropsCore.php b/src/PhpWord/Reader/Word2007/DocPropsCore.php index fd943875..a6a8902b 100644 --- a/src/PhpWord/Reader/Word2007/DocPropsCore.php +++ b/src/PhpWord/Reader/Word2007/DocPropsCore.php @@ -9,10 +9,13 @@ namespace PhpOffice\PhpWord\Reader\Word2007; +use PhpOffice\PhpWord\PhpWord; +use PhpOffice\PhpWord\Shared\XMLReader; + /** * Core properties reader */ -class DocPropsCore extends DocProps +class DocPropsCore extends AbstractPart { /** * Property mapping @@ -37,4 +40,34 @@ class DocPropsCore extends DocProps * @var array */ protected $callbacks = array('dcterms:created' => 'strtotime', 'dcterms:modified' => 'strtotime'); + + /** + * Read core/extended document properties + * + * @param \PhpOffice\PhpWord\PhpWord $phpWord + */ + public function read(PhpWord &$phpWord) + { + $xmlReader = new XMLReader(); + $xmlReader->getDomFromZip($this->docFile, $this->xmlFile); + + $docProps = $phpWord->getDocumentProperties(); + + $nodes = $xmlReader->getElements('*'); + if ($nodes->length > 0) { + foreach ($nodes as $node) { + if (!array_key_exists($node->nodeName, $this->mapping)) { + continue; + } + $method = $this->mapping[$node->nodeName]; + $value = $node->nodeValue == '' ? null : $node->nodeValue; + if (array_key_exists($node->nodeName, $this->callbacks)) { + $value = $this->callbacks[$node->nodeName]($value); + } + if (method_exists($docProps, $method)) { + $docProps->$method($value); + } + } + } + } } diff --git a/src/PhpWord/Reader/Word2007/Notes.php b/src/PhpWord/Reader/Word2007/Notes.php index bdb0b9e8..f92388dc 100644 --- a/src/PhpWord/Reader/Word2007/Notes.php +++ b/src/PhpWord/Reader/Word2007/Notes.php @@ -32,8 +32,8 @@ class Notes extends AbstractPart public function read(PhpWord &$phpWord) { $this->type = ($this->type == 'endnotes') ? 'endnotes' : 'footnotes'; - $collectionClass = 'PhpOffice\\PhpWord\\' . ucfirst($this->type); - $collection = $collectionClass::getElements(); + $getMethod = 'get' . $this->type; + $collection = $phpWord->$getMethod()->getItems(); $xmlReader = new XMLReader(); $xmlReader->getDomFromZip($this->docFile, $this->xmlFile); @@ -49,9 +49,10 @@ class Notes extends AbstractPart $element = $collection[$id]; $pNodes = $xmlReader->getElements('w:p/*', $node); foreach ($pNodes as $pNode) { - $this->readRun($xmlReader, $pNode, $element, $type); + $this->readRun($xmlReader, $pNode, $element, $this->type); } - $collectionClass::setElement($id, $element); + $addMethod = 'add' . ($this->type == 'endnotes' ? 'endnote' : 'footnote'); + $phpWord->$addMethod($element); } } } diff --git a/src/PhpWord/Style/TOC.php b/src/PhpWord/Style/TOC.php index e8a781b0..5333a0b6 100644 --- a/src/PhpWord/Style/TOC.php +++ b/src/PhpWord/Style/TOC.php @@ -12,26 +12,12 @@ namespace PhpOffice\PhpWord\Style; /** * TOC style */ -class TOC extends AbstractStyle +class TOC extends Tab { - const TABLEADER_DOT = 'dot'; - const TABLEADER_UNDERSCORE = 'underscore'; - const TABLEADER_LINE = 'hyphen'; - const TABLEADER_NONE = ''; - - /** - * Tab Leader - * - * @var string - */ - private $tabLeader; - - /** - * Tab Position - * - * @var int - */ - private $tabPos; + const TABLEADER_DOT = self::TAB_LEADER_DOT; + const TABLEADER_UNDERSCORE = self::TAB_LEADER_UNDERSCORE; + const TABLEADER_LINE = self::TAB_LEADER_HYPHEN; + const TABLEADER_NONE = self::TAB_LEADER_NONE; /** * Indent @@ -46,8 +32,7 @@ class TOC extends AbstractStyle */ public function __construct() { - $this->tabPos = 9062; - $this->tabLeader = self::TABLEADER_DOT; + parent::__construct(self::TAB_STOP_RIGHT, 9062, self::TABLEADER_DOT); $this->indent = 200; } @@ -58,17 +43,17 @@ class TOC extends AbstractStyle */ public function getTabPos() { - return $this->tabPos; + return $this->getPosition(); } /** * Set Tab Position * - * @param int $pValue + * @param int $value */ - public function setTabPos($pValue) + public function setTabPos($value) { - $this->tabPos = $pValue; + $this->position = $value; } /** @@ -78,17 +63,17 @@ class TOC extends AbstractStyle */ public function getTabLeader() { - return $this->tabLeader; + return $this->getLeader(); } /** * Set Tab Leader * - * @param string $pValue + * @param string $value */ - public function setTabLeader($pValue = self::TABLEADER_DOT) + public function setTabLeader($value = self::TABLEADER_DOT) { - $this->tabLeader = $pValue; + $this->leader = $value; } /** @@ -104,10 +89,10 @@ class TOC extends AbstractStyle /** * Set Indent * - * @param string $pValue + * @param string $value */ - public function setIndent($pValue) + public function setIndent($value) { - $this->indent = $pValue; + $this->indent = $value; } } diff --git a/src/PhpWord/Style/Tab.php b/src/PhpWord/Style/Tab.php index dfcb3b95..62785cfb 100644 --- a/src/PhpWord/Style/Tab.php +++ b/src/PhpWord/Style/Tab.php @@ -44,7 +44,7 @@ class Tab extends AbstractStyle * * @var string */ - private $val = self::TAB_STOP_CLEAR; + private $type = self::TAB_STOP_CLEAR; /** * Tab leader character @@ -54,22 +54,22 @@ class Tab extends AbstractStyle private $leader = self::TAB_LEADER_NONE; /** - * Tab stop position + * Tab stop position (twip) * - * @var int + * @var int|float */ private $position = 0; /** - * Create a new instance of Tab. Both $val and $leader + * Create a new instance of Tab. Both $type and $leader * must conform to the values put forth in the schema. If they do not * they will be changed to default values. * - * @param string $val Defaults to 'clear' if value is not possible. + * @param string $type Defaults to 'clear' if value is not possible. * @param int $position Must be numeric; otherwise defaults to 0. * @param string $leader Defaults to null if value is not possible. */ - public function __construct($val = null, $position = 0, $leader = null) + public function __construct($type = null, $position = 0, $leader = null) { $stopTypes = array( self::TAB_STOP_CLEAR, self::TAB_STOP_LEFT,self::TAB_STOP_CENTER, @@ -80,7 +80,7 @@ class Tab extends AbstractStyle self::TAB_LEADER_UNDERSCORE, self::TAB_LEADER_HEAVY, self::TAB_LEADER_MIDDLEDOT ); - $this->val = $this->setEnumVal($val, $stopTypes, $this->val); + $this->type = $this->setEnumVal($type, $stopTypes, $this->type); $this->position = $this->setNumericVal($position, $this->position); $this->leader = $this->setEnumVal($leader, $leaderTypes, $this->leader); } @@ -90,9 +90,21 @@ class Tab extends AbstractStyle * * @return string */ - public function getStopType() + public function getType() { - return $this->val; + return $this->type; + } + + /** + * Set stop type + * + * @param string $value + */ + public function setType($value) + { + $enum = array(self::TAB_STOP_CLEAR, self::TAB_STOP_LEFT, self::TAB_STOP_CENTER, + self::TAB_STOP_RIGHT, self::TAB_STOP_DECIMAL, self::TAB_STOP_BAR, self::TAB_STOP_NUM); + $this->type = $this->setEnumVal($value, $enum, $this->type); } /** @@ -105,13 +117,35 @@ class Tab extends AbstractStyle return $this->leader; } + /** + * Set leader + * + * @param string $value + */ + public function setLeader($value) + { + $enum = array(self::TAB_LEADER_NONE, self::TAB_LEADER_DOT, self::TAB_LEADER_HYPHEN, + self::TAB_LEADER_UNDERSCORE, self::TAB_LEADER_HEAVY, self::TAB_LEADER_MIDDLEDOT); + $this->leader = $this->setEnumVal($value, $enum, $this->leader); + } + /** * Get position * - * @return integer + * @return int|float */ public function getPosition() { return $this->position; } + + /** + * Set position + * + * @param int|float $value + */ + public function setPosition($value) + { + $this->position = $this->setNumericVal($value, $this->position); + } } diff --git a/src/PhpWord/TOC.php b/src/PhpWord/TOC.php index ea75c10d..577fe4ab 100644 --- a/src/PhpWord/TOC.php +++ b/src/PhpWord/TOC.php @@ -11,6 +11,12 @@ namespace PhpOffice\PhpWord; /** * Table of contents + * + * This static class has been deprecated and replaced by Collection\Titles. + * File maintained for backward compatibility and will be removed on 1.0. + * + * @deprecated 0.10.0 + * @codeCoverageIgnore */ class TOC { diff --git a/src/PhpWord/Writer/HTML.php b/src/PhpWord/Writer/HTML.php index d4b8adb3..a11a92ff 100644 --- a/src/PhpWord/Writer/HTML.php +++ b/src/PhpWord/Writer/HTML.php @@ -167,14 +167,16 @@ class HTML extends AbstractWriter implements WriterInterface */ private function writeNotes() { + $phpWord = $this->getPhpWord(); $html = ''; + if (!empty($this->notes)) { $html .= "