diff --git a/.scrutinizer.yml b/.scrutinizer.yml index a35530a9..6f982d8e 100644 --- a/.scrutinizer.yml +++ b/.scrutinizer.yml @@ -16,8 +16,9 @@ tools: external_code_coverage: enabled: true timeout: 900 - php_sim: - min_mass: 40 + php_cpd: true + # php_sim: # Temporarily disabled to allow focus on things other than duplicates + # min_mass: 40 php_pdepend: true php_analyzer: true sensiolabs_security_checker: true diff --git a/CHANGELOG.md b/CHANGELOG.md index 4f687b9d..30551204 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,8 @@ This release marked the change of PHPWord license from LGPL 2.1 to LGPL 3; new r - RTF: Ability to add links and page breaks in RTF - @ivanlanin GH-196 - ListItemRun: Remove fontStyle parameter because ListItemRun is inherited from TextRun and TextRun doesn't have fontStyle - @ivanlanin - Config: Ability to use a config file to store various common settings - @ivanlanin GH-200 +- ODT: Enable inline font style in TextRun - @ivanlanin +- ODT: Enable underline, strike/doublestrike, smallcaps/allcaps, superscript/subscript font style - @ivanlanin ### Bugfixes diff --git a/phpunit.xml.dist b/phpunit.xml.dist index fb511bd2..015dd2ed 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -18,7 +18,6 @@ ./src ./src/PhpWord/Shared/PCLZip - ./src/PhpWord/Shared/Spyc diff --git a/samples/resources/Sample_11_ReadWord2007.docx b/samples/resources/Sample_11_ReadWord2007.docx index aefe9f48..a457c7a6 100644 Binary files a/samples/resources/Sample_11_ReadWord2007.docx and b/samples/resources/Sample_11_ReadWord2007.docx differ diff --git a/src/PhpWord/PhpWord.php b/src/PhpWord/PhpWord.php index a3abb869..c54faa36 100644 --- a/src/PhpWord/PhpWord.php +++ b/src/PhpWord/PhpWord.php @@ -240,10 +240,11 @@ class PhpWord * Set default paragraph style definition to styles.xml * * @param array $styles Paragraph style definition + * @return \PhpOffice\PhpWord\Style\Paragraph */ public function setDefaultParagraphStyle($styles) { - Style::setDefaultParagraphStyle($styles); + return Style::setDefaultParagraphStyle($styles); } /** @@ -251,10 +252,11 @@ class PhpWord * * @param string $styleName * @param array $styles + * @return \PhpOffice\PhpWord\Style\Paragraph */ public function addParagraphStyle($styleName, $styles) { - Style::addParagraphStyle($styleName, $styles); + return Style::addParagraphStyle($styleName, $styles); } /** @@ -263,10 +265,11 @@ class PhpWord * @param string $styleName * @param mixed $fontStyle * @param mixed $paragraphStyle + * @return \PhpOffice\PhpWord\Style\Font */ public function addFontStyle($styleName, $fontStyle, $paragraphStyle = null) { - Style::addFontStyle($styleName, $fontStyle, $paragraphStyle); + return Style::addFontStyle($styleName, $fontStyle, $paragraphStyle); } /** @@ -275,10 +278,35 @@ class PhpWord * @param string $styleName * @param mixed $styleTable * @param mixed $styleFirstRow + * @return \PhpOffice\PhpWord\Style\Table */ public function addTableStyle($styleName, $styleTable, $styleFirstRow = null) { - Style::addTableStyle($styleName, $styleTable, $styleFirstRow); + return Style::addTableStyle($styleName, $styleTable, $styleFirstRow); + } + + /** + * Adds a numbering style + * + * @param string $styleName + * @param mixed $styles + * @return \PhpOffice\PhpWord\Style\Numbering + */ + public function addNumberingStyle($styleName, $styles) + { + return Style::addNumberingStyle($styleName, $styles); + } + + /** + * Adds a hyperlink style to styles.xml + * + * @param string $styleName + * @param mixed $styles + * @return \PhpOffice\PhpWord\Style\Font + */ + public function addLinkStyle($styleName, $styles) + { + return Style::addLinkStyle($styleName, $styles); } /** @@ -287,32 +315,11 @@ class PhpWord * @param int $depth * @param mixed $fontStyle * @param mixed $paragraphStyle + * @return \PhpOffice\PhpWord\Style\Font */ public function addTitleStyle($depth, $fontStyle, $paragraphStyle = null) { - Style::addTitleStyle($depth, $fontStyle, $paragraphStyle); - } - - /** - * Adds a hyperlink style to styles.xml - * - * @param string $styleName - * @param mixed $styles - */ - public function addLinkStyle($styleName, $styles) - { - Style::addLinkStyle($styleName, $styles); - } - - /** - * Adds a numbering style - * - * @param string $styleName - * @param mixed $styles - */ - public function addNumberingStyle($styleName, $styles) - { - Style::addNumberingStyle($styleName, $styles); + return Style::addTitleStyle($depth, $fontStyle, $paragraphStyle); } /** diff --git a/src/PhpWord/Reader/Word2007/AbstractPart.php b/src/PhpWord/Reader/Word2007/AbstractPart.php index 34088b17..b4b5d829 100644 --- a/src/PhpWord/Reader/Word2007/AbstractPart.php +++ b/src/PhpWord/Reader/Word2007/AbstractPart.php @@ -222,10 +222,11 @@ abstract class AbstractPart $style = array(); $mapping = array( 'w:rStyle' => 'styleName', - 'w:b' => 'bold', 'w:i' => 'italic', 'w:color' => 'color', - 'w:strike' => 'strikethrough', 'w:u' => 'underline', + 'w:b' => 'bold', 'w:i' => 'italic', 'w:color' => 'color', 'w:u' => 'underline', + 'w:strike' => 'strikethrough', 'w:dstrike' => 'doubleStrikethrough', 'w:highlight' => 'fgColor', 'w:sz' => 'size', 'w:rFonts' => 'name', 'w:vertAlign' => 'superScript', + 'w:smallCaps' => 'smallCaps', 'w:caps' => 'allCaps', ); $nodes = $xmlReader->getElements('w:rPr/*', $domNode); @@ -244,6 +245,9 @@ abstract class AbstractPart case 'w:b': case 'w:i': case 'w:strike': + case 'w:dstrike': + case 'w:smallCaps': + case 'w:caps': $style[$property] = true; break; diff --git a/src/PhpWord/Style.php b/src/PhpWord/Style.php index ef3310d7..d56c73fe 100644 --- a/src/PhpWord/Style.php +++ b/src/PhpWord/Style.php @@ -17,6 +17,7 @@ namespace PhpOffice\PhpWord; +use PhpOffice\PhpWord\Style\AbstractStyle; use PhpOffice\PhpWord\Style\Font; use PhpOffice\PhpWord\Style\Numbering; use PhpOffice\PhpWord\Style\Paragraph; @@ -39,10 +40,11 @@ class Style * * @param string $styleName * @param array $styles + * @return \PhpOffice\PhpWord\Style\Paragraph */ public static function addParagraphStyle($styleName, $styles) { - self::setStyleValues($styleName, new Paragraph(), $styles); + return self::setStyleValues($styleName, new Paragraph(), $styles); } /** @@ -51,10 +53,11 @@ class Style * @param string $styleName * @param array $fontStyle * @param array $paragraphStyle + * @return \PhpOffice\PhpWord\Style\Font */ public static function addFontStyle($styleName, $fontStyle, $paragraphStyle = null) { - self::setStyleValues($styleName, new Font('text', $paragraphStyle), $fontStyle); + return self::setStyleValues($styleName, new Font('text', $paragraphStyle), $fontStyle); } /** @@ -62,22 +65,24 @@ class Style * * @param string $styleName * @param array $styles + * @return \PhpOffice\PhpWord\Style\Font */ public static function addLinkStyle($styleName, $styles) { - self::setStyleValues($styleName, new Font('link'), $styles); + return self::setStyleValues($styleName, new Font('link'), $styles); } /** - * Add table style + * Add numbering style * * @param string $styleName - * @param array $styleTable - * @param array|null $styleFirstRow + * @param array $styleValues + * @return \PhpOffice\PhpWord\Style\Numbering + * @since 0.10.0 */ - public static function addTableStyle($styleName, $styleTable, $styleFirstRow = null) + public static function addNumberingStyle($styleName, $styleValues) { - self::setStyleValues($styleName, new Table($styleTable, $styleFirstRow), null); + return self::setStyleValues($styleName, new Numbering(), $styleValues); } /** @@ -86,29 +91,30 @@ class Style * @param int $depth * @param array $fontStyle * @param array $paragraphStyle + * @return \PhpOffice\PhpWord\Style\Font */ public static function addTitleStyle($depth, $fontStyle, $paragraphStyle = null) { - self::setStyleValues("Heading_{$depth}", new Font('title', $paragraphStyle), $fontStyle); + return self::setStyleValues("Heading_{$depth}", new Font('title', $paragraphStyle), $fontStyle); } /** - * Add numbering style + * Add table style * * @param string $styleName - * @param array $styleValues - * @return Numbering - * @since 0.10.0 + * @param array $styleTable + * @param array|null $styleFirstRow + * @return \PhpOffice\PhpWord\Style\Table */ - public static function addNumberingStyle($styleName, $styleValues) + public static function addTableStyle($styleName, $styleTable, $styleFirstRow = null) { - self::setStyleValues($styleName, new Numbering(), $styleValues); + return self::setStyleValues($styleName, new Table($styleTable, $styleFirstRow), null); } /** * Count styles * - * @return integer + * @return int * @since 0.10.0 */ public static function countStyles() @@ -129,16 +135,17 @@ class Style * Set default paragraph style * * @param array $styles Paragraph style definition + * @return \PhpOffice\PhpWord\Style\Paragraph */ public static function setDefaultParagraphStyle($styles) { - self::addParagraphStyle('Normal', $styles); + return self::addParagraphStyle('Normal', $styles); } /** * Get all styles * - * @return array + * @return \PhpOffice\PhpWord\Style\AbstractStyle[] */ public static function getStyles() { @@ -149,7 +156,7 @@ class Style * Get style by name * * @param string $styleName - * @return Paragraph|Font|Table|Numbering|null + * @return \PhpOffice\PhpWord\Style\AbstractStyle Paragraph|Font|Table|Numbering */ public static function getStyle($styleName) { @@ -163,21 +170,30 @@ class Style /** * Set style values and put it to static style collection * - * @param string $styleName - * @param Paragraph|Font|Table|Numbering $styleObject - * @param array|null $styleValues + * The $styleValues could be an array or object + * + * @param string $name + * @param \PhpOffice\PhpWord\Style\AbstractStyle $style + * @param array|\PhpOffice\PhpWord\Style\AbstractStyle $value + * @return \PhpOffice\PhpWord\Style\AbstractStyle */ - private static function setStyleValues($styleName, $styleObject, $styleValues = null) + private static function setStyleValues($name, $style, $value = null) { - if (!array_key_exists($styleName, self::$styles)) { - if (!is_null($styleValues) && is_array($styleValues)) { - foreach ($styleValues as $key => $value) { - $styleObject->setStyleValue($key, $value); + if (!array_key_exists($name, self::$styles)) { + if ($value !== null) { + if (is_array($value)) { + $style->setStyleByArray($value); + } elseif ($value instanceof AbstractStyle) { + if (get_class($style) == get_class($value)) { + $style = $value; + } } } - $styleObject->setStyleName($styleName); - $styleObject->setIndex(self::countStyles() + 1); // One based index - self::$styles[$styleName] = $styleObject; + $style->setStyleName($name); + $style->setIndex(self::countStyles() + 1); // One based index + self::$styles[$name] = $style; } + + return self::getStyle($name); } } diff --git a/src/PhpWord/Style/AbstractStyle.php b/src/PhpWord/Style/AbstractStyle.php index 0ac71ab2..c9e26887 100644 --- a/src/PhpWord/Style/AbstractStyle.php +++ b/src/PhpWord/Style/AbstractStyle.php @@ -49,6 +49,14 @@ abstract class AbstractStyle */ protected $aliases = array(); + /** + * Is this an automatic style? (Used primarily in OpenDocument driver) + * + * @var bool + * @since 0.11.0 + */ + private $isAuto = false; + /** * Get style name * @@ -95,6 +103,29 @@ abstract class AbstractStyle return $this; } + /** + * Get is automatic style flag + * + * @return bool + */ + public function isAuto() + { + return $this->isAuto; + } + + /** + * Set is automatic style flag + * + * @param bool $value + * @return self + */ + public function setAuto($value = true) + { + $this->isAuto = $this->setBoolVal($value, $this->isAuto); + + return $this; + } + /** * Set style value template method * @@ -123,12 +154,12 @@ abstract class AbstractStyle /** * Set style by using associative array * - * @param array $styles + * @param array $values * @return self */ - public function setStyleByArray($styles = array()) + public function setStyleByArray($values = array()) { - foreach ($styles as $key => $value) { + foreach ($values as $key => $value) { $this->setStyleValue($key, $value); } diff --git a/src/PhpWord/Writer/HTML/Element/Table.php b/src/PhpWord/Writer/HTML/Element/Table.php index fc5f0d30..c8813a67 100644 --- a/src/PhpWord/Writer/HTML/Element/Table.php +++ b/src/PhpWord/Writer/HTML/Element/Table.php @@ -41,9 +41,10 @@ class Table extends AbstractElement if ($rowCount > 0) { $content .= '' . PHP_EOL; foreach ($rows as $row) { - // $height = $row->getHeight(); + /** @var $row \PhpOffice\PhpWord\Element\Row Type hint */ $rowStyle = $row->getStyle(); - $tblHeader = $rowStyle->getTblHeader(); + // $height = $row->getHeight(); + $tblHeader = $rowStyle->isTblHeader(); $content .= '' . PHP_EOL; foreach ($row->getCells() as $cell) { $writer = new Container($this->parentWriter, $cell); diff --git a/src/PhpWord/Writer/ODText.php b/src/PhpWord/Writer/ODText.php index dc2c5d2c..fbe51c5d 100644 --- a/src/PhpWord/Writer/ODText.php +++ b/src/PhpWord/Writer/ODText.php @@ -49,6 +49,7 @@ class ODText extends AbstractWriter implements WriterInterface foreach (array_keys($this->parts) as $partName) { $partClass = get_class($this) . '\\Part\\' . $partName; if (class_exists($partClass)) { + /** @var $partObject \PhpOffice\PhpWord\Writer\ODText\Part\AbstractPart Type hint */ $partObject = new $partClass(); $partObject->setParentWriter($this); $this->writerParts[strtolower($partName)] = $partObject; diff --git a/src/PhpWord/Writer/ODText/Element/Table.php b/src/PhpWord/Writer/ODText/Element/Table.php index 19e5b408..f26960b8 100644 --- a/src/PhpWord/Writer/ODText/Element/Table.php +++ b/src/PhpWord/Writer/ODText/Element/Table.php @@ -49,6 +49,7 @@ class Table extends AbstractElement foreach ($rows as $row) { $xmlWriter->startElement('table:table-row'); + /** @var $row \PhpOffice\PhpWord\Element\Row Type hint */ foreach ($row->getCells() as $cell) { $xmlWriter->startElement('table:table-cell'); $xmlWriter->writeAttribute('office:value-type', 'string'); diff --git a/src/PhpWord/Writer/ODText/Element/Title.php b/src/PhpWord/Writer/ODText/Element/Title.php new file mode 100644 index 00000000..9d062a7f --- /dev/null +++ b/src/PhpWord/Writer/ODText/Element/Title.php @@ -0,0 +1,42 @@ +getXmlWriter(); + $element = $this->getElement(); + if (!$element instanceof \PhpOffice\PhpWord\Element\Title) { + return; + } + + $xmlWriter->startElement('text:p'); + $xmlWriter->writeRaw($element->getText()); + $xmlWriter->endElement(); // text:p + } +} diff --git a/src/PhpWord/Writer/ODText/Part/Content.php b/src/PhpWord/Writer/ODText/Part/Content.php index f5ae1883..f63deba6 100644 --- a/src/PhpWord/Writer/ODText/Part/Content.php +++ b/src/PhpWord/Writer/ODText/Part/Content.php @@ -19,12 +19,13 @@ namespace PhpOffice\PhpWord\Writer\ODText\Part; use PhpOffice\PhpWord\Element\Table; use PhpOffice\PhpWord\Element\Text; +use PhpOffice\PhpWord\Element\TextRun; use PhpOffice\PhpWord\Media; use PhpOffice\PhpWord\PhpWord; use PhpOffice\PhpWord\Shared\XMLWriter; +use PhpOffice\PhpWord\Style; use PhpOffice\PhpWord\Style\Font; use PhpOffice\PhpWord\Style\Paragraph; -use PhpOffice\PhpWord\Style; use PhpOffice\PhpWord\Writer\ODText\Element\Container; /** @@ -39,8 +40,10 @@ class Content extends AbstractPart */ public function write() { - $phpWord = $this->getParentWriter()->getPhpWord(); $xmlWriter = $this->getXmlWriter(); + $phpWord = $this->getParentWriter()->getPhpWord(); + + $this->getAutoStyles($phpWord); $xmlWriter->startDocument('1.0', 'UTF-8'); $xmlWriter->startElement('office:document-content'); @@ -51,14 +54,20 @@ class Content extends AbstractPart $xmlWriter->writeAttribute('xmlns:field', 'urn:openoffice:names:experimental:ooo-ms-interop:xmlns:field:1.0'); $xmlWriter->writeAttribute('xmlns:formx', 'urn:openoffice:names:experimental:ooxml-odf-interop:xmlns:form:1.0'); - $this->getAutomaticStyles($phpWord); $this->writeFontFaces($xmlWriter); // office:font-face-decls - $this->writeAutomaticStyles($xmlWriter, $phpWord); // office:automatic-styles + // Automatic styles + $xmlWriter->startElement('office:automatic-styles'); + $this->writeTextAutoStyles($xmlWriter); + $this->writeImageAutoStyles($xmlWriter); + $this->writeTableAutoStyles($xmlWriter, $phpWord); + $xmlWriter->endElement(); // office:automatic-styles + + // Body $xmlWriter->startElement('office:body'); $xmlWriter->startElement('office:text'); - // text:sequence-decls + // Sequence declarations $sequences = array('Illustration', 'Table', 'Text', 'Drawing'); $xmlWriter->startElement('text:sequence-decls'); foreach ($sequences as $sequence) { @@ -69,18 +78,18 @@ class Content extends AbstractPart } $xmlWriter->endElement(); // text:sequence-decl + // Sections $sections = $phpWord->getSections(); - $sectionCount = count($sections); - if ($sectionCount > 0) { - foreach ($sections as $section) { - // $xmlWriter->startElement('text:section'); - $containerWriter = new Container($xmlWriter, $section); - $containerWriter->write(); - // $xmlWriter->endElement(); // text:section - } + foreach ($sections as $section) { + // $xmlWriter->startElement('text:section'); + $containerWriter = new Container($xmlWriter, $section); + $containerWriter->write(); + // $xmlWriter->endElement(); // text:section } + $xmlWriter->endElement(); // office:text $xmlWriter->endElement(); // office:body + $xmlWriter->endElement(); // office:document-content return $xmlWriter->getData(); @@ -89,22 +98,16 @@ class Content extends AbstractPart /** * Write automatic styles */ - private function writeAutomaticStyles(XMLWriter $xmlWriter, PhpWord $phpWord) + private function writeTextAutoStyles(XMLWriter $xmlWriter) { - $xmlWriter->startElement('office:automatic-styles'); - - // Font and paragraph $styles = Style::getStyles(); $paragraphStyleCount = 0; if (count($styles) > 0) { - foreach ($styles as $styleName => $style) { - if (preg_match('#^T[0-9]+$#', $styleName) != 0 - || preg_match('#^P[0-9]+$#', $styleName) != 0 - ) { + foreach ($styles as $style) { + if ($style->isAuto() === true) { $styleClass = str_replace('\\Style\\', '\\Writer\\ODText\\Style\\', get_class($style)); if (class_exists($styleClass)) { $styleWriter = new $styleClass($xmlWriter, $style); - $styleWriter->setIsAuto(true); $styleWriter->write(); } if ($style instanceof Paragraph) { @@ -115,13 +118,18 @@ class Content extends AbstractPart if ($paragraphStyleCount == 0) { $style = new Paragraph(); $style->setStyleName('P1'); + $style->setAuto(); $styleWriter = new \PhpOffice\PhpWord\Writer\ODText\Style\Paragraph($xmlWriter, $style); - $styleWriter->setIsAuto(true); $styleWriter->write(); } } + } - // Images + /** + * Write image automatic styles + */ + private function writeImageAutoStyles(XMLWriter $xmlWriter) + { $images = Media::getElements('section'); foreach ($images as $image) { if ($image['type'] == 'image') { @@ -132,75 +140,94 @@ class Content extends AbstractPart $xmlWriter->startElement('style:graphic-properties'); $xmlWriter->writeAttribute('style:vertical-pos', 'top'); $xmlWriter->writeAttribute('style:vertical-rel', 'baseline'); - $xmlWriter->endElement(); - $xmlWriter->endElement(); + $xmlWriter->endElement(); // style:graphic-properties + $xmlWriter->endElement(); // style:style } } - - // Tables - $sections = $phpWord->getSections(); - $sectionCount = count($sections); - if ($sectionCount > 0) { - $sectionId = 0; - foreach ($sections as $section) { - $sectionId++; - $elements = $section->getElements(); - foreach ($elements as $element) { - if ($elements instanceof Table) { - $xmlWriter->startElement('style:style'); - $xmlWriter->writeAttribute('style:name', $element->getElementId()); - $xmlWriter->writeAttribute('style:family', 'table'); - $xmlWriter->startElement('style:table-properties'); - //$xmlWriter->writeAttribute('style:width', 'table'); - $xmlWriter->writeAttribute('style:rel-width', 100); - $xmlWriter->writeAttribute('table:align', 'center'); - $xmlWriter->endElement(); - $xmlWriter->endElement(); - } - } - } - } - - $xmlWriter->endElement(); // office:automatic-styles } /** - * Set automatic styles + * Write table automatic styles */ - private function getAutomaticStyles(PhpWord $phpWord) + private function writeTableAutoStyles(XMLWriter $xmlWriter, PhpWord $phpWord) { $sections = $phpWord->getSections(); - $sectionCount = count($sections); - if ($sectionCount > 0) { - $paragraphStyleCount = 0; - $fontStyleCount = 0; - foreach ($sections as $section) { - $elements = $section->getElements(); - foreach ($elements as $element) { - if ($element instanceof Text) { - $fontStyle = $element->getFontStyle(); - $paragraphStyle = $element->getParagraphStyle(); - - // Font - if ($fontStyle instanceof Font) { - $fontStyleCount++; - $arrStyle = array( - 'color' => $fontStyle->getColor(), - 'name' => $fontStyle->getName() - ); - $phpWord->addFontStyle('T' . $fontStyleCount, $arrStyle); - $element->setFontStyle('T' . $fontStyleCount); - - // Paragraph - } elseif ($paragraphStyle instanceof Paragraph) { - $paragraphStyleCount++; - - $phpWord->addParagraphStyle('P' . $paragraphStyleCount, array()); - $element->setParagraphStyle('P' . $paragraphStyleCount); - } - } + foreach ($sections as $section) { + $elements = $section->getElements(); + foreach ($elements as $element) { + if ($elements instanceof Table) { + $xmlWriter->startElement('style:style'); + $xmlWriter->writeAttribute('style:name', $element->getElementId()); + $xmlWriter->writeAttribute('style:family', 'table'); + $xmlWriter->startElement('style:table-properties'); + //$xmlWriter->writeAttribute('style:width', 'table'); + $xmlWriter->writeAttribute('style:rel-width', 100); + $xmlWriter->writeAttribute('table:align', 'center'); + $xmlWriter->endElement(); + $xmlWriter->endElement(); } } } } + + /** + * Get automatic styles + */ + private function getAutoStyles(PhpWord $phpWord) + { + $sections = $phpWord->getSections(); + $paragraphStyleCount = 0; + $fontStyleCount = 0; + foreach ($sections as $section) { + $this->getContainerStyle($section, $paragraphStyleCount, $fontStyleCount); + } + } + + /** + * Get all styles of each elements in container recursively + * + * @param \PhpOffice\PhpWord\Element\AbstractContainer $container + * @param int $paragraphStyleCount + * @param int $fontStyleCount + */ + private function getContainerStyle($container, &$paragraphStyleCount, &$fontStyleCount) + { + $elements = $container->getElements(); + foreach ($elements as $element) { + if ($element instanceof TextRun) { + $this->getContainerStyle($element, $paragraphStyleCount, $fontStyleCount); + } elseif ($element instanceof Text) { + $this->getElementStyle($element, $paragraphStyleCount, $fontStyleCount); + } + } + } + + /** + * Get style of individual element + * + * @param \PhpOffice\PhpWord\Element\Text $element + * @param int $paragraphStyleCount + * @param int $fontStyleCount + */ + private function getElementStyle(&$element, &$paragraphStyleCount, &$fontStyleCount) + { + $fontStyle = $element->getFontStyle(); + $paragraphStyle = $element->getParagraphStyle(); + $phpWord = $this->getParentWriter()->getPhpWord(); + + // Font + if ($fontStyle instanceof Font) { + $fontStyleCount++; + $style = $phpWord->addFontStyle("T{$fontStyleCount}", $fontStyle); + $style->setAuto(); + $element->setFontStyle("T{$fontStyleCount}"); + + // Paragraph + } elseif ($paragraphStyle instanceof Paragraph) { + $paragraphStyleCount++; + $style = $phpWord->addParagraphStyle("P{$paragraphStyleCount}", array()); + $style->setAuto(); + $element->setParagraphStyle("P{$paragraphStyleCount}"); + } + } } diff --git a/src/PhpWord/Writer/ODText/Part/Styles.php b/src/PhpWord/Writer/ODText/Part/Styles.php index 0c39607c..a226f7ff 100644 --- a/src/PhpWord/Writer/ODText/Part/Styles.php +++ b/src/PhpWord/Writer/ODText/Part/Styles.php @@ -17,8 +17,7 @@ namespace PhpOffice\PhpWord\Writer\ODText\Part; -use PhpOffice\PhpWord\Settings; -use PhpOffice\PhpWord\Style; +use PhpOffice\PhpWord\Shared\XMLWriter; /** * ODText styloes part writer: styles.xml @@ -36,128 +35,39 @@ class Styles extends AbstractPart // XML header $xmlWriter->startDocument('1.0', 'UTF-8'); - - // Styles:Styles $xmlWriter->startElement('office:document-styles'); $this->writeCommonRootAttributes($xmlWriter); - // office:font-face-decls + // Font declarations $this->writeFontFaces($xmlWriter); - // office:styles + // Office styles $xmlWriter->startElement('office:styles'); - - // style:default-style - $xmlWriter->startElement('style:default-style'); - $xmlWriter->writeAttribute('style:family', 'paragraph'); - - // style:paragraph-properties - $xmlWriter->startElement('style:paragraph-properties'); - $xmlWriter->writeAttribute('fo:hyphenation-ladder-count', 'no-limit'); - $xmlWriter->writeAttribute('style:text-autospace', 'ideograph-alpha'); - $xmlWriter->writeAttribute('style:punctuation-wrap', 'hanging'); - $xmlWriter->writeAttribute('style:line-break', 'strict'); - $xmlWriter->writeAttribute('style:tab-stop-distance', '1.249cm'); - $xmlWriter->writeAttribute('style:writing-mode', 'page'); + $this->writePart($xmlWriter, 'Default'); + $this->writePart($xmlWriter, 'Named'); $xmlWriter->endElement(); - // style:text-properties - $xmlWriter->startElement('style:text-properties'); - $xmlWriter->writeAttribute('style:use-window-font-color', 'true'); - $xmlWriter->writeAttribute('style:font-name', Settings::getDefaultFontName()); - $xmlWriter->writeAttribute('fo:font-size', Settings::getDefaultFontSize() . 'pt'); - $xmlWriter->writeAttribute('fo:language', 'fr'); - $xmlWriter->writeAttribute('fo:country', 'FR'); - $xmlWriter->writeAttribute('style:letter-kerning', 'true'); - $xmlWriter->writeAttribute('style:font-name-asian', Settings::getDefaultFontName() . '2'); - $xmlWriter->writeAttribute('style:font-size-asian', Settings::getDefaultFontSize() . 'pt'); - $xmlWriter->writeAttribute('style:language-asian', 'zh'); - $xmlWriter->writeAttribute('style:country-asian', 'CN'); - $xmlWriter->writeAttribute('style:font-name-complex', Settings::getDefaultFontName() . '2'); - $xmlWriter->writeAttribute('style:font-size-complex', Settings::getDefaultFontSize() . 'pt'); - $xmlWriter->writeAttribute('style:language-complex', 'hi'); - $xmlWriter->writeAttribute('style:country-complex', 'IN'); - $xmlWriter->writeAttribute('fo:hyphenate', 'false'); - $xmlWriter->writeAttribute('fo:hyphenation-remain-char-count', '2'); - $xmlWriter->writeAttribute('fo:hyphenation-push-char-count', '2'); - $xmlWriter->endElement(); - - $xmlWriter->endElement(); - - // Write Style Definitions - $styles = Style::getStyles(); - if (count($styles) > 0) { - foreach ($styles as $styleName => $style) { - if (preg_match('#^T[0-9]+$#', $styleName) == 0 - && preg_match('#^P[0-9]+$#', $styleName) == 0 - ) { - $styleClass = str_replace('\\Style\\', '\\Writer\\ODText\\Style\\', get_class($style)); - if (class_exists($styleClass)) { - $styleWriter = new $styleClass($xmlWriter, $style); - $styleWriter->write(); - } - } - } - } - $xmlWriter->endElement(); - - // office:automatic-styles + // Automatic styles $xmlWriter->startElement('office:automatic-styles'); - // style:page-layout - $xmlWriter->startElement('style:page-layout'); - $xmlWriter->writeAttribute('style:name', 'Mpm1'); - // style:page-layout-properties - $xmlWriter->startElement('style:page-layout-properties'); - $xmlWriter->writeAttribute('fo:page-width', "21.001cm"); - $xmlWriter->writeAttribute('fo:page-height', '29.7cm'); - $xmlWriter->writeAttribute('style:num-format', '1'); - $xmlWriter->writeAttribute('style:print-orientation', 'portrait'); - $xmlWriter->writeAttribute('fo:margin-top', '2.501cm'); - $xmlWriter->writeAttribute('fo:margin-bottom', '2cm'); - $xmlWriter->writeAttribute('fo:margin-left', '2.501cm'); - $xmlWriter->writeAttribute('fo:margin-right', '2.501cm'); - $xmlWriter->writeAttribute('style:writing-mode', 'lr-tb'); - $xmlWriter->writeAttribute('style:layout-grid-color', '#c0c0c0'); - $xmlWriter->writeAttribute('style:layout-grid-lines', '25199'); - $xmlWriter->writeAttribute('style:layout-grid-base-height', '0.423cm'); - $xmlWriter->writeAttribute('style:layout-grid-ruby-height', '0cm'); - $xmlWriter->writeAttribute('style:layout-grid-mode', 'none'); - $xmlWriter->writeAttribute('style:layout-grid-ruby-below', 'false'); - $xmlWriter->writeAttribute('style:layout-grid-print', 'false'); - $xmlWriter->writeAttribute('style:layout-grid-display', 'false'); - $xmlWriter->writeAttribute('style:layout-grid-base-width', '0.37cm'); - $xmlWriter->writeAttribute('style:layout-grid-snap-to', 'true'); - $xmlWriter->writeAttribute('style:footnote-max-height', '0cm'); - //style:footnote-sep - $xmlWriter->startElement('style:footnote-sep'); - $xmlWriter->writeAttribute('style:width', '0.018cm'); - $xmlWriter->writeAttribute('style:line-style', 'solid'); - $xmlWriter->writeAttribute('style:adjustment', 'left'); - $xmlWriter->writeAttribute('style:rel-width', '25%'); - $xmlWriter->writeAttribute('style:color', '#000000'); - $xmlWriter->endElement(); - $xmlWriter->endElement(); - // style:header-style - $xmlWriter->startElement('style:header-style'); - $xmlWriter->endElement(); - // style:footer-style - $xmlWriter->startElement('style:footer-style'); - $xmlWriter->endElement(); - $xmlWriter->endElement(); + $this->writePart($xmlWriter, 'PageLayout'); + $this->writePart($xmlWriter, 'Master'); $xmlWriter->endElement(); - // office:master-styles - $xmlWriter->startElement('office:master-styles'); - // style:master-page - $xmlWriter->startElement('style:master-page'); - $xmlWriter->writeAttribute('style:name', 'Standard'); - $xmlWriter->writeAttribute('style:page-layout-name', 'Mpm1'); - $xmlWriter->endElement(); - $xmlWriter->endElement(); + $xmlWriter->endElement(); // office:document-styles - $xmlWriter->endElement(); - - // Return return $xmlWriter->getData(); } + + /** + * Write style part + * + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @param string $subStyle + */ + private function writePart(XMLWriter $xmlWriter, $subStyle) + { + $writerClass = "PhpOffice\\PhpWord\\Writer\\ODText\\Style\\{$subStyle}Style"; + $styleWriter = new $writerClass($xmlWriter); + $styleWriter->write(); + } } diff --git a/src/PhpWord/Writer/ODText/Style/DefaultStyle.php b/src/PhpWord/Writer/ODText/Style/DefaultStyle.php new file mode 100644 index 00000000..d77157fa --- /dev/null +++ b/src/PhpWord/Writer/ODText/Style/DefaultStyle.php @@ -0,0 +1,72 @@ +getXmlWriter(); + + $xmlWriter->startElement('style:default-style'); + $xmlWriter->writeAttribute('style:family', 'paragraph'); + + // Paragraph + $xmlWriter->startElement('style:paragraph-properties'); + $xmlWriter->writeAttribute('fo:hyphenation-ladder-count', 'no-limit'); + $xmlWriter->writeAttribute('style:text-autospace', 'ideograph-alpha'); + $xmlWriter->writeAttribute('style:punctuation-wrap', 'hanging'); + $xmlWriter->writeAttribute('style:line-break', 'strict'); + $xmlWriter->writeAttribute('style:tab-stop-distance', '1.249cm'); + $xmlWriter->writeAttribute('style:writing-mode', 'page'); + $xmlWriter->endElement(); // style:paragraph-properties + + // Font + $xmlWriter->startElement('style:text-properties'); + $xmlWriter->writeAttribute('style:use-window-font-color', 'true'); + $xmlWriter->writeAttribute('style:font-name', Settings::getDefaultFontName()); + $xmlWriter->writeAttribute('fo:font-size', Settings::getDefaultFontSize() . 'pt'); + $xmlWriter->writeAttribute('fo:language', 'fr'); + $xmlWriter->writeAttribute('fo:country', 'FR'); + $xmlWriter->writeAttribute('style:letter-kerning', 'true'); + $xmlWriter->writeAttribute('style:font-name-asian', Settings::getDefaultFontName() . '2'); + $xmlWriter->writeAttribute('style:font-size-asian', Settings::getDefaultFontSize() . 'pt'); + $xmlWriter->writeAttribute('style:language-asian', 'zh'); + $xmlWriter->writeAttribute('style:country-asian', 'CN'); + $xmlWriter->writeAttribute('style:font-name-complex', Settings::getDefaultFontName() . '2'); + $xmlWriter->writeAttribute('style:font-size-complex', Settings::getDefaultFontSize() . 'pt'); + $xmlWriter->writeAttribute('style:language-complex', 'hi'); + $xmlWriter->writeAttribute('style:country-complex', 'IN'); + $xmlWriter->writeAttribute('fo:hyphenate', 'false'); + $xmlWriter->writeAttribute('fo:hyphenation-remain-char-count', '2'); + $xmlWriter->writeAttribute('fo:hyphenation-push-char-count', '2'); + $xmlWriter->endElement(); // style:text-properties + + $xmlWriter->endElement(); // style:default-style + } +} diff --git a/src/PhpWord/Writer/ODText/Style/Font.php b/src/PhpWord/Writer/ODText/Style/Font.php index 148c8dbc..acab0ee5 100644 --- a/src/PhpWord/Writer/ODText/Style/Font.php +++ b/src/PhpWord/Writer/ODText/Style/Font.php @@ -24,11 +24,6 @@ namespace PhpOffice\PhpWord\Writer\ODText\Style; */ class Font extends AbstractStyle { - /** - * Is automatic style - */ - private $isAuto = false; - /** * Write style */ @@ -67,17 +62,28 @@ class Font extends AbstractStyle $xmlWriter->writeAttributeIf($style->isItalic(), 'style:font-style-asian', 'italic'); $xmlWriter->writeAttributeIf($style->isItalic(), 'style:font-style-complex', 'italic'); + // Underline + // @todo Various mode of underline + $underline = $style->getUnderline(); + $xmlWriter->writeAttributeIf($underline != 'none', 'style:text-underline-style', 'solid'); + + // Strikethrough, double strikethrough + $xmlWriter->writeAttributeIf($style->isStrikethrough(), 'style:text-line-through-type', 'single'); + $xmlWriter->writeAttributeIf($style->isDoubleStrikethrough(), 'style:text-line-through-type', 'double'); + + // Small caps, all caps + $xmlWriter->writeAttributeIf($style->isSmallCaps(), 'fo:font-variant', 'small-caps'); + $xmlWriter->writeAttributeIf($style->isAllCaps(), 'fo:text-transform', 'uppercase'); + + // Superscript/subscript + $xmlWriter->writeAttributeIf($style->isSuperScript(), 'style:text-position', 'super'); + $xmlWriter->writeAttributeIf($style->isSubScript(), 'style:text-position', 'sub'); + + // @todo Foreground-Color + + // @todo Background color + $xmlWriter->endElement(); // style:text-properties $xmlWriter->endElement(); // style:style } - - /** - * Set is automatic style - * - * @param bool $value - */ - public function setIsAuto($value) - { - $this->isAuto = $value; - } } diff --git a/src/PhpWord/Writer/ODText/Style/MasterStyle.php b/src/PhpWord/Writer/ODText/Style/MasterStyle.php new file mode 100644 index 00000000..97d91a6a --- /dev/null +++ b/src/PhpWord/Writer/ODText/Style/MasterStyle.php @@ -0,0 +1,43 @@ +getXmlWriter(); + + $xmlWriter->startElement('office:master-styles'); + + $xmlWriter->startElement('style:master-page'); + $xmlWriter->writeAttribute('style:name', 'Standard'); + $xmlWriter->writeAttribute('style:page-layout-name', 'Mpm1'); + $xmlWriter->endElement(); // style:master-page + + $xmlWriter->endElement(); // office:master-styles + } +} diff --git a/src/PhpWord/Writer/ODText/Style/NamedStyle.php b/src/PhpWord/Writer/ODText/Style/NamedStyle.php new file mode 100644 index 00000000..e2b63162 --- /dev/null +++ b/src/PhpWord/Writer/ODText/Style/NamedStyle.php @@ -0,0 +1,50 @@ +getXmlWriter(); + + $styles = Style::getStyles(); + if (count($styles) > 0) { + foreach ($styles as $style) { + if ($style->isAuto() === false) { + $styleClass = str_replace('\\Style\\', '\\Writer\\ODText\\Style\\', get_class($style)); + if (class_exists($styleClass)) { + /** @var $styleWriter \PhpOffice\PhpWord\Writer\ODText\Style\AbstractStyle Type hint */ + $styleWriter = new $styleClass($xmlWriter, $style); + $styleWriter->write(); + } + } + } + } + } +} diff --git a/src/PhpWord/Writer/ODText/Style/PageLayoutStyle.php b/src/PhpWord/Writer/ODText/Style/PageLayoutStyle.php new file mode 100644 index 00000000..cfcb6c3b --- /dev/null +++ b/src/PhpWord/Writer/ODText/Style/PageLayoutStyle.php @@ -0,0 +1,78 @@ +getXmlWriter(); + + $xmlWriter->startElement('style:page-layout'); + $xmlWriter->writeAttribute('style:name', 'Mpm1'); + + $xmlWriter->startElement('style:page-layout-properties'); + $xmlWriter->writeAttribute('fo:page-width', "21.001cm"); + $xmlWriter->writeAttribute('fo:page-height', '29.7cm'); + $xmlWriter->writeAttribute('style:num-format', '1'); + $xmlWriter->writeAttribute('style:print-orientation', 'portrait'); + $xmlWriter->writeAttribute('fo:margin-top', '2.501cm'); + $xmlWriter->writeAttribute('fo:margin-bottom', '2cm'); + $xmlWriter->writeAttribute('fo:margin-left', '2.501cm'); + $xmlWriter->writeAttribute('fo:margin-right', '2.501cm'); + $xmlWriter->writeAttribute('style:writing-mode', 'lr-tb'); + $xmlWriter->writeAttribute('style:layout-grid-color', '#c0c0c0'); + $xmlWriter->writeAttribute('style:layout-grid-lines', '25199'); + $xmlWriter->writeAttribute('style:layout-grid-base-height', '0.423cm'); + $xmlWriter->writeAttribute('style:layout-grid-ruby-height', '0cm'); + $xmlWriter->writeAttribute('style:layout-grid-mode', 'none'); + $xmlWriter->writeAttribute('style:layout-grid-ruby-below', 'false'); + $xmlWriter->writeAttribute('style:layout-grid-print', 'false'); + $xmlWriter->writeAttribute('style:layout-grid-display', 'false'); + $xmlWriter->writeAttribute('style:layout-grid-base-width', '0.37cm'); + $xmlWriter->writeAttribute('style:layout-grid-snap-to', 'true'); + $xmlWriter->writeAttribute('style:footnote-max-height', '0cm'); + + $xmlWriter->startElement('style:footnote-sep'); + $xmlWriter->writeAttribute('style:width', '0.018cm'); + $xmlWriter->writeAttribute('style:line-style', 'solid'); + $xmlWriter->writeAttribute('style:adjustment', 'left'); + $xmlWriter->writeAttribute('style:rel-width', '25%'); + $xmlWriter->writeAttribute('style:color', '#000000'); + $xmlWriter->endElement(); //style:footnote-sep + + $xmlWriter->endElement(); // style:page-layout-properties + + + $xmlWriter->startElement('style:header-style'); + $xmlWriter->endElement(); // style:header-style + + $xmlWriter->startElement('style:footer-style'); + $xmlWriter->endElement(); // style:footer-style + + $xmlWriter->endElement(); // style:page-layout + } +} diff --git a/src/PhpWord/Writer/ODText/Style/Paragraph.php b/src/PhpWord/Writer/ODText/Style/Paragraph.php index e5f52cfe..133b8cdf 100644 --- a/src/PhpWord/Writer/ODText/Style/Paragraph.php +++ b/src/PhpWord/Writer/ODText/Style/Paragraph.php @@ -24,11 +24,6 @@ namespace PhpOffice\PhpWord\Writer\ODText\Style; */ class Paragraph extends AbstractStyle { - /** - * Is automatic style - */ - private $isAuto = false; - /** * Write style */ @@ -46,13 +41,13 @@ class Paragraph extends AbstractStyle $xmlWriter->startElement('style:style'); $xmlWriter->writeAttribute('style:name', $style->getStyleName()); $xmlWriter->writeAttribute('style:family', 'paragraph'); - if ($this->isAuto) { + if ($style->isAuto()) { $xmlWriter->writeAttribute('style:parent-style-name', 'Standard'); $xmlWriter->writeAttribute('style:master-page-name', 'Standard'); } $xmlWriter->startElement('style:paragraph-properties'); - if ($this->isAuto) { + if ($style->isAuto()) { $xmlWriter->writeAttribute('style:page-number', 'auto'); } else { $xmlWriter->writeAttribute('fo:margin-top', $marginTop . 'cm'); @@ -63,14 +58,4 @@ class Paragraph extends AbstractStyle $xmlWriter->endElement(); //style:style } - - /** - * Set is automatic style - * - * @param bool $value - */ - public function setIsAuto($value) - { - $this->isAuto = $value; - } } diff --git a/src/PhpWord/Writer/Word2007/Part/AbstractPart.php b/src/PhpWord/Writer/Word2007/Part/AbstractPart.php index b0454956..04444155 100644 --- a/src/PhpWord/Writer/Word2007/Part/AbstractPart.php +++ b/src/PhpWord/Writer/Word2007/Part/AbstractPart.php @@ -19,7 +19,7 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Part; use PhpOffice\PhpWord\Exception\Exception; use PhpOffice\PhpWord\Shared\XMLWriter; -use PhpOffice\PhpWord\Writer\WriterInterface; +use PhpOffice\PhpWord\Writer\AbstractWriter; /** * Word2007 writer part abstract class @@ -29,16 +29,16 @@ abstract class AbstractPart /** * Parent writer * - * @var \PhpOffice\PhpWord\Writer\WriterInterface + * @var \PhpOffice\PhpWord\Writer\AbstractWriter */ protected $parentWriter; /** * Set parent writer * - * @param \PhpOffice\PhpWord\Writer\WriterInterface $writer + * @param \PhpOffice\PhpWord\Writer\AbstractWriter $writer */ - public function setParentWriter(WriterInterface $writer = null) + public function setParentWriter(AbstractWriter $writer = null) { $this->parentWriter = $writer; } @@ -46,7 +46,7 @@ abstract class AbstractPart /** * Get parent writer * - * @return \PhpOffice\PhpWord\Writer\WriterInterface + * @return \PhpOffice\PhpWord\Writer\AbstractWriter * @throws \PhpOffice\PhpWord\Exception\Exception */ public function getParentWriter() diff --git a/tests/PhpWord/Tests/Writer/ODText/ElementTest.php b/tests/PhpWord/Tests/Writer/ODText/ElementTest.php index c5fdfb41..fa9532d1 100644 --- a/tests/PhpWord/Tests/Writer/ODText/ElementTest.php +++ b/tests/PhpWord/Tests/Writer/ODText/ElementTest.php @@ -28,7 +28,7 @@ class ElementTest extends \PHPUnit_Framework_TestCase */ public function testUnmatchedElements() { - $elements = array('Image', 'Link', 'Table', 'Text'); + $elements = array('Image', 'Link', 'Table', 'Text', 'Title'); foreach ($elements as $element) { $objectClass = 'PhpOffice\\PhpWord\\Writer\\ODText\\Element\\' . $element; $xmlWriter = new XMLWriter();