Нет описания

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252
  1. <?php
  2. /**
  3. * This file is part of PHPWord - A pure PHP library for reading and writing
  4. * word processing documents.
  5. *
  6. * PHPWord is free software distributed under the terms of the GNU Lesser
  7. * General Public License version 3 as published by the Free Software Foundation.
  8. *
  9. * For the full copyright and license information, please read the LICENSE
  10. * file that was distributed with this source code. For the full list of
  11. * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.
  12. *
  13. * @link https://github.com/PHPOffice/PHPWord
  14. * @copyright 2010-2014 PHPWord contributors
  15. * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3
  16. */
  17. namespace PhpOffice\PhpWord\Writer\ODText\Part;
  18. use PhpOffice\PhpWord\Element\Image;
  19. use PhpOffice\PhpWord\Element\Table;
  20. use PhpOffice\PhpWord\Element\Text;
  21. use PhpOffice\PhpWord\Element\TextRun;
  22. use PhpOffice\PhpWord\PhpWord;
  23. use PhpOffice\PhpWord\Shared\XMLWriter;
  24. use PhpOffice\PhpWord\Style;
  25. use PhpOffice\PhpWord\Style\Font;
  26. use PhpOffice\PhpWord\Style\Paragraph;
  27. use PhpOffice\PhpWord\Style\Table as TableStyle;
  28. use PhpOffice\PhpWord\Writer\ODText\Element\Container;
  29. use PhpOffice\PhpWord\Writer\ODText\Style\Paragraph as ParagraphStyleWriter;
  30. /**
  31. * ODText content part writer: content.xml
  32. */
  33. class Content extends AbstractPart
  34. {
  35. /**
  36. * Auto style collection
  37. *
  38. * Collect inline style information from section, image, and table elements
  39. *
  40. * @todo Merge font and paragraph styles
  41. * @var array
  42. */
  43. private $autoStyles = array('Section' => array(), 'Image' => array(), 'Table' => array());
  44. /**
  45. * Write part
  46. *
  47. * @return string
  48. */
  49. public function write()
  50. {
  51. $xmlWriter = $this->getXmlWriter();
  52. $phpWord = $this->getParentWriter()->getPhpWord();
  53. $this->getAutoStyles($phpWord);
  54. $xmlWriter->startDocument('1.0', 'UTF-8');
  55. $xmlWriter->startElement('office:document-content');
  56. $this->writeCommonRootAttributes($xmlWriter);
  57. $xmlWriter->writeAttribute('xmlns:xforms', 'http://www.w3.org/2002/xforms');
  58. $xmlWriter->writeAttribute('xmlns:xsd', 'http://www.w3.org/2001/XMLSchema');
  59. $xmlWriter->writeAttribute('xmlns:xsi', 'http://www.w3.org/2001/XMLSchema-instance');
  60. $xmlWriter->writeAttribute('xmlns:field', 'urn:openoffice:names:experimental:ooo-ms-interop:xmlns:field:1.0');
  61. $xmlWriter->writeAttribute('xmlns:formx', 'urn:openoffice:names:experimental:ooxml-odf-interop:xmlns:form:1.0');
  62. // Font declarations and automatic styles
  63. $this->writeFontFaces($xmlWriter); // office:font-face-decls
  64. $this->writeAutoStyles($xmlWriter); // office:automatic-styles
  65. // Body
  66. $xmlWriter->startElement('office:body');
  67. $xmlWriter->startElement('office:text');
  68. // Sequence declarations
  69. $sequences = array('Illustration', 'Table', 'Text', 'Drawing');
  70. $xmlWriter->startElement('text:sequence-decls');
  71. foreach ($sequences as $sequence) {
  72. $xmlWriter->startElement('text:sequence-decl');
  73. $xmlWriter->writeAttribute('text:display-outline-level', 0);
  74. $xmlWriter->writeAttribute('text:name', $sequence);
  75. $xmlWriter->endElement();
  76. }
  77. $xmlWriter->endElement(); // text:sequence-decl
  78. // Sections
  79. $sections = $phpWord->getSections();
  80. foreach ($sections as $section) {
  81. $name = 'Section' . $section->getSectionId();
  82. $xmlWriter->startElement('text:section');
  83. $xmlWriter->writeAttribute('text:name', $name);
  84. $xmlWriter->writeAttribute('text:style-name', $name);
  85. $containerWriter = new Container($xmlWriter, $section);
  86. $containerWriter->write();
  87. $xmlWriter->endElement(); // text:section
  88. }
  89. $xmlWriter->endElement(); // office:text
  90. $xmlWriter->endElement(); // office:body
  91. $xmlWriter->endElement(); // office:document-content
  92. return $xmlWriter->getData();
  93. }
  94. /**
  95. * Write automatic styles other than fonts and paragraphs.
  96. *
  97. * @since 0.11.0
  98. *
  99. * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter
  100. * @return void
  101. */
  102. private function writeAutoStyles(XMLWriter $xmlWriter)
  103. {
  104. $xmlWriter->startElement('office:automatic-styles');
  105. $this->writeTextStyles($xmlWriter);
  106. foreach ($this->autoStyles as $element => $styles) {
  107. $writerClass = 'PhpOffice\\PhpWord\\Writer\\ODText\\Style\\' . $element;
  108. foreach ($styles as $style) {
  109. /** @var \PhpOffice\PhpWord\Writer\ODText\Style\AbstractStyle $styleWriter Type hint */
  110. $styleWriter = new $writerClass($xmlWriter, $style);
  111. $styleWriter->write();
  112. }
  113. }
  114. $xmlWriter->endElement(); // office:automatic-styles
  115. }
  116. /**
  117. * Write automatic styles.
  118. *
  119. * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter
  120. * @return void
  121. */
  122. private function writeTextStyles(XMLWriter $xmlWriter)
  123. {
  124. $styles = Style::getStyles();
  125. $paragraphStyleCount = 0;
  126. if (count($styles) > 0) {
  127. foreach ($styles as $style) {
  128. if ($style->isAuto() === true) {
  129. $styleClass = str_replace('\\Style\\', '\\Writer\\ODText\\Style\\', get_class($style));
  130. if (class_exists($styleClass)) {
  131. /** @var \PhpOffice\PhpWord\Writer\ODText\Style\AbstractStyle $styleWriter Type hint */
  132. $styleWriter = new $styleClass($xmlWriter, $style);
  133. $styleWriter->write();
  134. }
  135. if ($style instanceof Paragraph) {
  136. $paragraphStyleCount++;
  137. }
  138. }
  139. }
  140. if ($paragraphStyleCount == 0) {
  141. $style = new Paragraph();
  142. $style->setStyleName('P1');
  143. $style->setAuto();
  144. $styleWriter = new ParagraphStyleWriter($xmlWriter, $style);
  145. $styleWriter->write();
  146. }
  147. }
  148. }
  149. /**
  150. * Get automatic styles.
  151. *
  152. * @param \PhpOffice\PhpWord\PhpWord $phpWord
  153. * @return void
  154. */
  155. private function getAutoStyles(PhpWord $phpWord)
  156. {
  157. $sections = $phpWord->getSections();
  158. $paragraphStyleCount = 0;
  159. $fontStyleCount = 0;
  160. foreach ($sections as $section) {
  161. $style = $section->getStyle();
  162. $style->setStyleName("Section{$section->getSectionId()}");
  163. $this->autoStyles['Section'][] = $style;
  164. $this->getContainerStyle($section, $paragraphStyleCount, $fontStyleCount);
  165. }
  166. }
  167. /**
  168. * Get all styles of each elements in container recursively
  169. *
  170. * Table style can be null or string of the style name
  171. *
  172. * @param \PhpOffice\PhpWord\Element\AbstractContainer $container
  173. * @param int &$paragraphStyleCount
  174. * @param int &$fontStyleCount
  175. * @return void
  176. * @todo Simplify the logic
  177. */
  178. private function getContainerStyle($container, &$paragraphStyleCount, &$fontStyleCount)
  179. {
  180. $elements = $container->getElements();
  181. foreach ($elements as $element) {
  182. if ($element instanceof TextRun) {
  183. $this->getContainerStyle($element, $paragraphStyleCount, $fontStyleCount);
  184. } elseif ($element instanceof Text) {
  185. $this->getElementStyle($element, $paragraphStyleCount, $fontStyleCount);
  186. } elseif ($element instanceof Image) {
  187. $style = $element->getStyle();
  188. $style->setStyleName('fr' . $element->getMediaIndex());
  189. $this->autoStyles['Image'][] = $style;
  190. } elseif ($element instanceof Table) {
  191. $style = $element->getStyle();
  192. if ($style === null) {
  193. $style = new TableStyle();
  194. } elseif (is_string($style)) {
  195. $style = Style::getStyle($style);
  196. }
  197. $style->setStyleName($element->getElementId());
  198. $this->autoStyles['Table'][] = $style;
  199. }
  200. }
  201. }
  202. /**
  203. * Get style of individual element
  204. *
  205. * @param \PhpOffice\PhpWord\Element\Text &$element
  206. * @param int &$paragraphStyleCount
  207. * @param int &$fontStyleCount
  208. * @return void
  209. */
  210. private function getElementStyle(&$element, &$paragraphStyleCount, &$fontStyleCount)
  211. {
  212. $fontStyle = $element->getFontStyle();
  213. $paragraphStyle = $element->getParagraphStyle();
  214. $phpWord = $this->getParentWriter()->getPhpWord();
  215. // Font
  216. if ($fontStyle instanceof Font) {
  217. $fontStyleCount++;
  218. $style = $phpWord->addFontStyle("T{$fontStyleCount}", $fontStyle);
  219. $style->setAuto();
  220. $element->setFontStyle("T{$fontStyleCount}");
  221. // Paragraph
  222. } elseif ($paragraphStyle instanceof Paragraph) {
  223. $paragraphStyleCount++;
  224. $style = $phpWord->addParagraphStyle("P{$paragraphStyleCount}", array());
  225. $style->setAuto();
  226. $element->setParagraphStyle("P{$paragraphStyleCount}");
  227. }
  228. }
  229. }