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); return $textObject; } /** * Add textrun element * * @param mixed $paragraphStyle * @return TextRun */ public function addTextRun($paragraphStyle = null) { $this->checkValidity('textrun'); $textRun = new TextRun($paragraphStyle); $textRun->setDocPart($this->getDocPart(), $this->getDocPartId()); $this->addElement($textRun); return $textRun; } /** * Add link element * * @param string $linkSrc * @param string $linkName * @param mixed $fontStyle * @param mixed $paragraphStyle * @return Link */ public function addLink($linkSrc, $linkName = null, $fontStyle = null, $paragraphStyle = null) { $this->checkValidity('link'); $elementDocPart = $this->checkElementDocPart(); $link = new Link(String::toUTF8($linkSrc), String::toUTF8($linkName), $fontStyle, $paragraphStyle); $link->setDocPart($this->getDocPart(), $this->getDocPartId()); $rId = Media::addElement($elementDocPart, 'link', $linkSrc); $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 = TOC::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 */ public function addPreserveText($text, $fontStyle = null, $paragraphStyle = null) { $this->checkValidity('preservetext'); $preserveText = new PreserveText(String::toUTF8($text), $fontStyle, $paragraphStyle); $preserveText->setDocPart($this->getDocPart(), $this->getDocPartId()); $this->addElement($preserveText); return $preserveText; } /** * Add text break element * * @param int $count * @param mixed $fontStyle * @param mixed $paragraphStyle */ public function addTextBreak($count = 1, $fontStyle = null, $paragraphStyle = null) { $this->checkValidity('textbreak'); for ($i = 1; $i <= $count; $i++) { $textBreak = new TextBreak($fontStyle, $paragraphStyle); $textBreak->setDocPart($this->getDocPart(), $this->getDocPartId()); $this->addElement($textBreak); } } /** * Add listitem element * * @param string $text * @param int $depth * @param mixed $fontStyle * @param mixed $styleList * @param mixed $paragraphStyle * @return ListItem */ public function addListItem($text, $depth = 0, $fontStyle = null, $styleList = null, $paragraphStyle = null) { $this->checkValidity('listitem'); $listItem = new ListItem(String::toUTF8($text), $depth, $fontStyle, $styleList, $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 */ public function addImage($src, $style = null, $isWatermark = false) { $this->checkValidity('image'); $elementDocPart = $this->checkElementDocPart(); $image = new Image($src, $style, $isWatermark); $image->setDocPart($this->getDocPart(), $this->getDocPartId()); $rId = Media::addElement($elementDocPart, 'image', $src, $image); $image->setRelationId($rId); $this->addElement($image); return $image; } /** * Add OLE-object element * * All exceptions should be handled by \PhpOffice\PhpWord\Element\Object * * @param string $src * @param mixed $style * @return Object * @throws \PhpOffice\PhpWord\Exception\Exception * @todo Enable OLE object element in header and footer */ public function addObject($src, $style = null) { $this->checkValidity('object'); $elementDocPart = $this->checkElementDocPart(); $object = new Object($src, $style); $object->setDocPart($this->getDocPart(), $this->getDocPartId()); if (!is_null($object->getSource())) { $inf = pathinfo($src); $ext = $inf['extension']; if (strlen($ext) == 4 && strtolower(substr($ext, -1)) == 'x') { $ext = substr($ext, 0, -1); } $icon = realpath(__DIR__ . "/../_staticDocParts/_{$ext}.png"); $rId = Media::addElement($elementDocPart, 'object', $src); $object->setRelationId($rId); $rIdimg = Media::addElement($elementDocPart, 'image', $icon, new Image($icon)); $object->setImageRelationId($rIdimg); $this->addElement($object); return $object; } else { throw new InvalidObjectException(); } } /** * Add footnote element * * @param mixed $paragraphStyle * @return FootnoteElement */ public function addFootnote($paragraphStyle = null) { $this->checkValidity('footnote'); $footnote = new FootnoteElement($paragraphStyle); $rId = Footnotes::addElement($footnote); $footnote->setDocPart('footnote', $this->getDocPartId()); $footnote->setRelationId($rId); $this->addElement($footnote); return $footnote; } /** * Add endnote element * * @param mixed $paragraphStyle * @return 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; } /** * Add a CheckBox Element * * @param string $name * @param string $text * @param mixed $fontStyle * @param mixed $paragraphStyle * @return CheckBox */ public function addCheckBox($name, $text, $fontStyle = null, $paragraphStyle = null) { $this->checkValidity('checkbox'); $checkBox = new CheckBox(String::toUTF8($name), String::toUTF8($text), $fontStyle, $paragraphStyle); $checkBox->setDocPart($this->getDocPart(), $this->getDocPartId()); $this->addElement($checkBox); return $checkBox; } /** * Get section number * * @return integer */ public function getSectionId() { return $this->sectionId; } /** * Set doc part * * @param string $docPart * @param integer $docPartId */ public function setDocPart($docPart, $docPartId = 1) { $this->docPart = $docPart; $this->docPartId = $docPartId; } /** * Get doc part * * @return string */ public function getDocPart() { return $this->docPart; } /** * Get doc part Id * * @return integer */ public function getDocPartId() { return $this->docPartId; } /** * Set element index and unique id, and add element into elements collection */ protected function addElement(AbstractElement $element) { $element->setElementIndex($this->countElements() + 1); $element->setElementId(); $this->elements[] = $element; } /** * Get all elements * * @return array */ public function getElements() { return $this->elements; } /** * Count elements * * @return integer */ public function countElements() { return count($this->elements); } /** * Get element index * * @return int */ public function getElementIndex() { return $this->elementIndex; } /** * Set element index * * @param int $value */ public function setElementIndex($value) { $this->elementIndex = $value; } /** * Get element unique ID * * @return string */ public function getElementId() { return $this->elementId; } /** * Set element unique ID from 6 first digit of md5 */ public function setElementId() { $this->elementId = substr(md5(rand()), 0, 6); } /** * Get relation Id * * @return int */ public function getRelationId() { $this->checkValidity('relationid'); return $this->relationId; } /** * Set relation Id * * @param int $rId */ public function setRelationId($rId) { $this->checkValidity('relationid'); $this->relationId = $rId; } /** * Check if element is located in section doc part (as opposed to header/footer) * * @return boolean */ public function isInSection() { return ($this->docPart == 'section'); } /** * Set style value * * @param mixed $styleObject Style object * @param mixed $styleValue Style value * @param boolean $returnObject Always return object */ protected function setStyle($styleObject, $styleValue = null, $returnObject = false) { if (!is_null($styleValue) && is_array($styleValue)) { foreach ($styleValue as $key => $value) { $styleObject->setStyleValue($key, $value); } $style = $styleObject; } else { $style = $returnObject ? $styleObject : $styleValue; } return $style; } /** * Check if a method is allowed for the current container * * @param string $method * @return boolean */ private function checkValidity($method) { // 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'), ); // Special condition, e.g. preservetext can only exists in cell when // the cell is located in header or footer $validContainerInContainers = array( 'preservetext' => array(array('cell'), array('header', 'footer')), 'footnote' => array(array('cell', 'textrun'), array('section')), 'endnote' => array(array('cell', 'textrun'), array('section')), ); // Check if a method is valid for current container if (array_key_exists($method, $validContainers)) { if (!in_array($this->container, $validContainers[$method])) { throw new \BadMethodCallException(); } } // Check if a method is valid for current container, located in other container if (array_key_exists($method, $validContainerInContainers)) { $rules = $validContainerInContainers[$method]; $containers = $rules[0]; $allowedDocParts = $rules[1]; foreach ($containers as $container) { if ($this->container == $container && !in_array($this->getDocPart(), $allowedDocParts)) { throw new \BadMethodCallException(); } } } return true; } /** * Return element location in document: section, headerx, or footerx */ private function checkElementDocPart() { $isCellTextrun = in_array($this->container, array('cell', 'textrun')); $docPart = $isCellTextrun ? $this->getDocPart() : $this->container; $docPartId = $isCellTextrun ? $this->getDocPartId() : $this->sectionId; $inHeaderFooter = ($docPart == 'header' || $docPart == 'footer'); return $inHeaderFooter ? $docPart . $docPartId : $docPart; } /** * Add memory image element * * @param string $src * @param mixed $style * @deprecated 0.9.0 * @codeCoverageIgnore */ public function addMemoryImage($src, $style = null) { return $this->addImage($src, $style); } /** * Create textrun element * * @param mixed $paragraphStyle * @deprecated 0.10.0 * @codeCoverageIgnore */ public function createTextRun($paragraphStyle = null) { return $this->addTextRun($paragraphStyle); } /** * Create footnote element * * @param mixed $paragraphStyle * @deprecated 0.10.0 * @codeCoverageIgnore */ public function createFootnote($paragraphStyle = null) { return $this->addFootnote($paragraphStyle); } }