diff --git a/src/PhpWord/Autoloader.php b/src/PhpWord/Autoloader.php index 6acfff21..c60ae9a6 100644 --- a/src/PhpWord/Autoloader.php +++ b/src/PhpWord/Autoloader.php @@ -46,6 +46,7 @@ class Autoloader $file = str_replace('\\', DIRECTORY_SEPARATOR, substr($class, $prefixLength)); $file = realpath(__DIR__ . (empty($file) ? '' : DIRECTORY_SEPARATOR) . $file . '.php'); if (file_exists($file)) { + /** @noinspection PhpIncludeInspection Dynamic includes */ require_once $file; } } diff --git a/src/PhpWord/Reader/Word2007/Document.php b/src/PhpWord/Reader/Word2007/Document.php index 224c895e..80d2dde2 100644 --- a/src/PhpWord/Reader/Word2007/Document.php +++ b/src/PhpWord/Reader/Word2007/Document.php @@ -158,7 +158,9 @@ class Document extends AbstractPart // Section properties if ($xmlReader->elementExists('w:pPr/w:sectPr', $node)) { $sectPrNode = $xmlReader->getElement('w:pPr/w:sectPr', $node); - $this->readWSectPrNode($xmlReader, $sectPrNode, $section); + if ($sectPrNode !== null) { + $this->readWSectPrNode($xmlReader, $sectPrNode, $section); + } $section = $this->phpWord->addSection(); } } @@ -172,10 +174,8 @@ class Document extends AbstractPart */ private function readWSectPrNode(XMLReader $xmlReader, \DOMElement $node, Section &$section) { - if ($node !== null) { - $settings = $this->readSectionStyle($xmlReader, $node); - $section->setSettings($settings); - $this->readHeaderFooter($settings, $section); - } + $settings = $this->readSectionStyle($xmlReader, $node); + $section->setSettings($settings); + $this->readHeaderFooter($settings, $section); } } diff --git a/src/PhpWord/Shared/String.php b/src/PhpWord/Shared/String.php index 259e904c..99b8cca3 100644 --- a/src/PhpWord/Shared/String.php +++ b/src/PhpWord/Shared/String.php @@ -86,14 +86,28 @@ class String } /** - * Returns unicode from UTF8 text + * Returns unicode array from UTF8 text + * + * The function is splitted to reduce cyclomatic complexity * * @param string $text UTF8 text * @return string Unicode text * @since 0.11.0 - * @link http://www.randomchaos.com/documents/?source=php_and_unicode */ public static function toUnicode($text) + { + return self::unicodeToEntities(self::utf8ToUnicode($text)); + } + + /** + * Returns unicode from UTF8 text + * + * @param string $text UTF8 text + * @return array + * @since 0.11.0 + * @link http://www.randomchaos.com/documents/?source=php_and_unicode + */ + private static function utf8ToUnicode($text) { $unicode = array(); $values = array(); @@ -122,8 +136,21 @@ class String } } - // Converts text with utf8 characters into rtf utf8 entites preserving ascii + return $unicode; + } + + /** + * Returns entites from unicode array + * + * @param array $unicode + * @return string + * @since 0.11.0 + * @link http://www.randomchaos.com/documents/?source=php_and_unicode + */ + private static function unicodeToEntities($unicode) + { $entities = ''; + foreach ($unicode as $value) { if ($value != 65279) { $entities .= $value > 127 ? '\uc0{\u' . $value . '}' : chr($value); diff --git a/src/PhpWord/Writer/HTML.php b/src/PhpWord/Writer/HTML.php index 98cab55e..88e7658d 100644 --- a/src/PhpWord/Writer/HTML.php +++ b/src/PhpWord/Writer/HTML.php @@ -19,15 +19,6 @@ namespace PhpOffice\PhpWord\Writer; use PhpOffice\PhpWord\Exception\Exception; use PhpOffice\PhpWord\PhpWord; -use PhpOffice\PhpWord\Settings; -use PhpOffice\PhpWord\Style; -use PhpOffice\PhpWord\Style\Font; -use PhpOffice\PhpWord\Style\Paragraph; -use PhpOffice\PhpWord\Writer\HTML\Element\Container; -use PhpOffice\PhpWord\Writer\HTML\Element\TextRun as TextRunWriter; -use PhpOffice\PhpWord\Writer\HTML\Style\Font as FontStyleWriter; -use PhpOffice\PhpWord\Writer\HTML\Style\Generic as GenericStyleWriter; -use PhpOffice\PhpWord\Writer\HTML\Style\Paragraph as ParagraphStyleWriter; /** * HTML writer @@ -57,6 +48,17 @@ class HTML extends AbstractWriter implements WriterInterface public function __construct(PhpWord $phpWord = null) { $this->setPhpWord($phpWord); + + $this->parts = array('Head', 'Body'); + foreach ($this->parts as $partName) { + $partClass = 'PhpOffice\\PhpWord\\Writer\\HTML\\Part\\' . $partName; + if (class_exists($partClass)) { + /** @var \PhpOffice\PhpWord\Writer\HTML\Part\AbstractPart $part Type hint */ + $part = new $partClass(); + $part->setParentWriter($this); + $this->writerParts[strtolower($partName)] = $part; + } + } } /** @@ -89,164 +91,13 @@ class HTML extends AbstractWriter implements WriterInterface $content .= '' . PHP_EOL; $content .= '' . PHP_EOL; $content .= '' . PHP_EOL; - $content .= '' . PHP_EOL; - $content .= $this->writeHead(); - $content .= '' . PHP_EOL; - $content .= '' . PHP_EOL; - $content .= $this->writeBody(); - $content .= $this->writeNotes(); - $content .= '' . PHP_EOL; + $content .= $this->getWriterPart('Head')->write(); + $content .= $this->getWriterPart('Body')->write(); $content .= '' . PHP_EOL; return $content; } - /** - * Generate HTML header - * - * @return string - */ - private function writeHead() - { - $phpWord = $this->getPhpWord(); - $properties = $phpWord->getDocumentProperties(); - $propertiesMapping = array( - 'creator' => 'author', - 'title' => '', - 'description' => '', - 'subject' => '', - 'keywords' => '', - 'category' => '', - 'company' => '', - 'manager' => '' - ); - $title = $properties->getTitle(); - $title = ($title != '') ? $title : 'PHPWord'; - - $content = ''; - $content .= '' . PHP_EOL; - $content .= '' . htmlspecialchars($title) . '' . PHP_EOL; - foreach ($propertiesMapping as $key => $value) { - $value = ($value == '') ? $key : $value; - $method = "get" . $key; - if ($properties->$method() != '') { - $content .= '' . PHP_EOL; - } - } - $content .= $this->writeStyles(); - - return $content; - } - - /** - * Get content - * - * @return string - */ - private function writeBody() - { - $phpWord = $this->getPhpWord(); - $content = ''; - - $sections = $phpWord->getSections(); - $countSections = count($sections); - - if ($countSections > 0) { - foreach ($sections as $section) { - $writer = new Container($this, $section); - $content .= $writer->write(); - } - } - - return $content; - } - - /** - * Get styles - * - * @return string - */ - private function writeStyles() - { - $css = '' . PHP_EOL; - - return $css; - } - - /** - * Write footnote/endnote contents as textruns - */ - private function writeNotes() - { - $phpWord = $this->getPhpWord(); - $content = PHP_EOL; - - if (!empty($this->notes)) { - $content .= "
" . PHP_EOL; - foreach ($this->notes as $noteId => $noteMark) { - list($noteType, $noteTypeId) = explode('-', $noteMark); - $method = 'get' . ($noteType == 'endnote' ? 'Endnotes' : 'Footnotes'); - $collection = $phpWord->$method()->getItems(); - - if (array_key_exists($noteTypeId, $collection)) { - $element = $collection[$noteTypeId]; - $noteAnchor = ""; - $noteAnchor .= "{$noteId}"; - - $writer = new TextRunWriter($this, $element); - $writer->setOpeningText($noteAnchor); - $content .= $writer->write(); - } - } - } - - return $content; - } - /** * Get is PDF * diff --git a/src/PhpWord/Writer/HTML/Element/Image.php b/src/PhpWord/Writer/HTML/Element/Image.php index dafc1c38..698b7e86 100644 --- a/src/PhpWord/Writer/HTML/Element/Image.php +++ b/src/PhpWord/Writer/HTML/Element/Image.php @@ -88,7 +88,7 @@ class Image extends Text } else { $actualSource = $source; } - if (is_null($actualSource)) { + if ($actualSource === null) { return null; } @@ -100,12 +100,13 @@ class Image extends Text $imageBinary = ob_get_contents(); ob_end_clean(); } else { - if ($fileHandle = fopen($actualSource, 'rb', false)) { + $fileHandle = fopen($actualSource, 'rb', false); + if ($fileHandle !== false) { $imageBinary = fread($fileHandle, filesize($actualSource)); fclose($fileHandle); } } - if (!is_null($imageBinary)) { + if ($imageBinary !== null) { $base64 = chunk_split(base64_encode($imageBinary)); $imageData = 'data:' . $imageType . ';base64,' . $base64; } diff --git a/src/PhpWord/Writer/HTML/Part/AbstractPart.php b/src/PhpWord/Writer/HTML/Part/AbstractPart.php new file mode 100644 index 00000000..319aa20f --- /dev/null +++ b/src/PhpWord/Writer/HTML/Part/AbstractPart.php @@ -0,0 +1,68 @@ +parentWriter = $writer; + } + + /** + * Get parent writer + * + * @return \PhpOffice\PhpWord\Writer\AbstractWriter + * @throws \PhpOffice\PhpWord\Exception\Exception + */ + public function getParentWriter() + { + if ($this->parentWriter !== null) { + return $this->parentWriter; + } else { + throw new Exception('No parent WriterInterface assigned.'); + } + } +} diff --git a/src/PhpWord/Writer/HTML/Part/Body.php b/src/PhpWord/Writer/HTML/Part/Body.php new file mode 100644 index 00000000..4fd61a83 --- /dev/null +++ b/src/PhpWord/Writer/HTML/Part/Body.php @@ -0,0 +1,89 @@ +getParentWriter()->getPhpWord(); + + $content = ''; + + $content .= '' . PHP_EOL; + $sections = $phpWord->getSections(); + foreach ($sections as $section) { + $writer = new Container($this->getParentWriter(), $section); + $content .= $writer->write(); + } + + $content .= $this->writeNotes(); + $content .= '' . PHP_EOL; + + return $content; + } + + /** + * Write footnote/endnote contents as textruns + * + * @return string + */ + private function writeNotes() + { + /** @var \PhpOffice\PhpWord\Writer\HTML $parentWriter Type hint */ + $parentWriter = $this->getParentWriter(); + $phpWord = $parentWriter->getPhpWord(); + $notes = $parentWriter->getNotes(); + + $content = ''; + + if (!empty($notes)) { + $content .= "
" . PHP_EOL; + foreach ($notes as $noteId => $noteMark) { + list($noteType, $noteTypeId) = explode('-', $noteMark); + $method = 'get' . ($noteType == 'endnote' ? 'Endnotes' : 'Footnotes'); + $collection = $phpWord->$method()->getItems(); + + if (array_key_exists($noteTypeId, $collection)) { + $element = $collection[$noteTypeId]; + $noteAnchor = ""; + $noteAnchor .= "{$noteId}"; + + $writer = new TextRunWriter($this->getParentWriter(), $element); + $writer->setOpeningText($noteAnchor); + $content .= $writer->write(); + } + } + } + + return $content; + } +} diff --git a/src/PhpWord/Writer/HTML/Part/Head.php b/src/PhpWord/Writer/HTML/Part/Head.php new file mode 100644 index 00000000..389d568b --- /dev/null +++ b/src/PhpWord/Writer/HTML/Part/Head.php @@ -0,0 +1,129 @@ +getParentWriter()->getPhpWord()->getDocumentProperties(); + $propertiesMapping = array( + 'creator' => 'author', + 'title' => '', + 'description' => '', + 'subject' => '', + 'keywords' => '', + 'category' => '', + 'company' => '', + 'manager' => '' + ); + $title = $docProps->getTitle(); + $title = ($title != '') ? $title : 'PHPWord'; + + $content = ''; + + $content .= '' . PHP_EOL; + $content .= '' . PHP_EOL; + $content .= '' . htmlspecialchars($title) . '' . PHP_EOL; + foreach ($propertiesMapping as $key => $value) { + $value = ($value == '') ? $key : $value; + $method = "get" . $key; + if ($docProps->$method() != '') { + $content .= '' . PHP_EOL; + } + } + $content .= $this->writeStyles(); + $content .= '' . PHP_EOL; + + return $content; + } + /** + * Get styles + * + * @return string + */ + private function writeStyles() + { + $css = '' . PHP_EOL; + + return $css; + } +} diff --git a/src/PhpWord/Writer/PDF/AbstractRenderer.php b/src/PhpWord/Writer/PDF/AbstractRenderer.php index f7266d1a..83b02251 100644 --- a/src/PhpWord/Writer/PDF/AbstractRenderer.php +++ b/src/PhpWord/Writer/PDF/AbstractRenderer.php @@ -84,6 +84,7 @@ abstract class AbstractRenderer extends HTML parent::__construct($phpWord); $includeFile = Settings::getPdfRendererPath() . '/' . $this->includeFile; if (file_exists($includeFile)) { + /** @noinspection PhpIncludeInspection Dynamic includes */ require_once $includeFile; } else { throw new Exception('Unable to load PDF Rendering library'); diff --git a/src/PhpWord/Writer/RTF.php b/src/PhpWord/Writer/RTF.php index aaf412de..ef94b264 100644 --- a/src/PhpWord/Writer/RTF.php +++ b/src/PhpWord/Writer/RTF.php @@ -35,7 +35,8 @@ class RTF extends AbstractWriter implements WriterInterface private $lastParagraphStyle; /** - * Create new RTF writer + * Create new instance + * * @param \PhpOffice\PhpWord\PhpWord $phpWord */ public function __construct(PhpWord $phpWord = null) @@ -52,7 +53,6 @@ class RTF extends AbstractWriter implements WriterInterface $this->writerParts[strtolower($partName)] = $part; } } - } /** diff --git a/src/PhpWord/Writer/RTF/Part/AbstractPart.php b/src/PhpWord/Writer/RTF/Part/AbstractPart.php index 3a73a226..b10e5654 100644 --- a/src/PhpWord/Writer/RTF/Part/AbstractPart.php +++ b/src/PhpWord/Writer/RTF/Part/AbstractPart.php @@ -17,52 +17,13 @@ namespace PhpOffice\PhpWord\Writer\RTF\Part; -use PhpOffice\PhpWord\Exception\Exception; -use PhpOffice\PhpWord\Writer\AbstractWriter; +use PhpOffice\PhpWord\Writer\HTML\Part\AbstractPart as HTMLAbstractPart; /** * Abstract RTF part writer * * @since 0.11.0 */ -abstract class AbstractPart +abstract class AbstractPart extends HTMLAbstractPart { - /** - * Parent writer - * - * @var \PhpOffice\PhpWord\Writer\AbstractWriter - */ - private $parentWriter; - - /** - * Write part - * - * @return string - */ - abstract public function write(); - - /** - * Set parent writer - * - * @param \PhpOffice\PhpWord\Writer\AbstractWriter $writer - */ - public function setParentWriter(AbstractWriter $writer = null) - { - $this->parentWriter = $writer; - } - - /** - * Get parent writer - * - * @return \PhpOffice\PhpWord\Writer\AbstractWriter - * @throws \PhpOffice\PhpWord\Exception\Exception - */ - public function getParentWriter() - { - if ($this->parentWriter !== null) { - return $this->parentWriter; - } else { - throw new Exception('No parent WriterInterface assigned.'); - } - } } diff --git a/src/PhpWord/Writer/Word2007/Element/Container.php b/src/PhpWord/Writer/Word2007/Element/Container.php index 7d1c8104..3dad824d 100644 --- a/src/PhpWord/Writer/Word2007/Element/Container.php +++ b/src/PhpWord/Writer/Word2007/Element/Container.php @@ -17,8 +17,10 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Element; +use PhpOffice\PhpWord\Element\AbstractElement as Element; use PhpOffice\PhpWord\Element\AbstractContainer as ContainerElement; use PhpOffice\PhpWord\Element\TextBreak as TextBreakElement; +use PhpOffice\PhpWord\Shared\XMLWriter; /** * Container element writer (section, textrun, header, footnote, cell, etc.) @@ -51,36 +53,52 @@ class Container extends AbstractElement $elements = $container->getElements(); $elementClass = ''; foreach ($elements as $element) { - $elementClass = substr(get_class($element), strrpos(get_class($element), '\\') + 1); - $writerClass = $this->namespace . '\\' . $elementClass; - - // Check it's a page break. No need to write it, instead, flag containers' pageBreakBefore - // to be assigned to the next element - if ($elementClass == 'PageBreak') { - $this->setPageBreakBefore(true); - continue; - } - if (class_exists($writerClass)) { - // Get container's page break before and reset it - $pageBreakBefore = $this->hasPageBreakBefore(); - $this->setPageBreakBefore(false); - - /** @var \PhpOffice\PhpWord\Writer\Word2007\Element\AbstractElement $writer Type hint */ - $writer = new $writerClass($xmlWriter, $element, $withoutP); - $writer->setPageBreakBefore($pageBreakBefore); - $writer->write(); - } + $elementClass = $this->writeElement($xmlWriter, $element, $withoutP); } - // Special case for Cell: They have to contain a w:p element at the end. The $elementClass contains - // the last element name. If it's empty string or Table, the last element is not w:p - if ($containerClass == 'Cell') { - if ($elementClass == '' || $elementClass == 'Table') { - $writerClass = $this->namespace . '\\TextBreak'; - /** @var \PhpOffice\PhpWord\Writer\Word2007\Element\AbstractElement $writer Type hint */ - $writer = new $writerClass($xmlWriter, new TextBreakElement(), $withoutP); - $writer->write(); - } + // Special case for Cell: They have to contain a w:p element at the end. + // The $elementClass contains the last element name. If it's empty string + // or Table, the last element is not w:p + $writeLastTextBreak = ($containerClass == 'Cell') && ($elementClass == '' || $elementClass == 'Table'); + if ($writeLastTextBreak) { + $writerClass = $this->namespace . '\\TextBreak'; + /** @var \PhpOffice\PhpWord\Writer\Word2007\Element\AbstractElement $writer Type hint */ + $writer = new $writerClass($xmlWriter, new TextBreakElement(), $withoutP); + $writer->write(); } } + + /** + * Write individual element + * + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Element\AbstractElement $element + * @param bool $withoutP + * @return string + */ + private function writeElement(XMLWriter $xmlWriter, Element $element, $withoutP) + { + $elementClass = substr(get_class($element), strrpos(get_class($element), '\\') + 1); + $writerClass = $this->namespace . '\\' . $elementClass; + + // Check it's a page break. No need to write it, instead, flag containers' + // pageBreakBefore to be assigned to the next element + if ($elementClass == 'PageBreak') { + $this->setPageBreakBefore(true); + return $elementClass; + } + + if (class_exists($writerClass)) { + // Get container's page break before and reset it + $pageBreakBefore = $this->hasPageBreakBefore(); + $this->setPageBreakBefore(false); + + /** @var \PhpOffice\PhpWord\Writer\Word2007\Element\AbstractElement $writer Type hint */ + $writer = new $writerClass($xmlWriter, $element, $withoutP); + $writer->setPageBreakBefore($pageBreakBefore); + $writer->write(); + } + + return $elementClass; + } }