Document.php 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  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. * @see https://github.com/PHPOffice/PHPWord
  14. * @copyright 2010-2018 PHPWord contributors
  15. * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3
  16. */
  17. namespace PhpOffice\PhpWord\Writer\RTF\Part;
  18. use PhpOffice\PhpWord\Element\Footer;
  19. use PhpOffice\PhpWord\Settings;
  20. use PhpOffice\PhpWord\Writer\RTF\Element\Container;
  21. use PhpOffice\PhpWord\Writer\RTF\Style\Section as SectionStyleWriter;
  22. /**
  23. * RTF document part writer
  24. *
  25. * @since 0.11.0
  26. * @see http://www.biblioscape.com/rtf15_spec.htm#Heading24
  27. */
  28. class Document extends AbstractPart
  29. {
  30. /**
  31. * Write part
  32. *
  33. * @return string
  34. */
  35. public function write()
  36. {
  37. $content = '';
  38. $content .= $this->writeInfo();
  39. $content .= $this->writeFormatting();
  40. $content .= $this->writeSections();
  41. return $content;
  42. }
  43. /**
  44. * Write document information
  45. *
  46. * @return string
  47. */
  48. private function writeInfo()
  49. {
  50. $docProps = $this->getParentWriter()->getPhpWord()->getDocInfo();
  51. $properties = array('title', 'subject', 'category', 'keywords', 'comment',
  52. 'author', 'operator', 'creatim', 'revtim', 'company', 'manager', );
  53. $mapping = array(
  54. 'comment' => 'description',
  55. 'author' => 'creator',
  56. 'operator' => 'lastModifiedBy',
  57. 'creatim' => 'created',
  58. 'revtim' => 'modified', );
  59. $dateFields = array('creatim', 'revtim');
  60. $content = '';
  61. $content .= '{';
  62. $content .= '\info';
  63. foreach ($properties as $property) {
  64. $method = 'get' . (isset($mapping[$property]) ? $mapping[$property] : $property);
  65. if (!in_array($property, $dateFields) && Settings::isOutputEscapingEnabled()) {
  66. $value = $this->escaper->escape($docProps->$method());
  67. } else {
  68. $value = $docProps->$method();
  69. }
  70. $value = in_array($property, $dateFields) ? $this->getDateValue($value) : $value;
  71. $content .= "{\\{$property} {$value}}";
  72. }
  73. $content .= '}';
  74. $content .= PHP_EOL;
  75. return $content;
  76. }
  77. /**
  78. * Write document formatting properties
  79. *
  80. * @return string
  81. */
  82. private function writeFormatting()
  83. {
  84. $docSettings = $this->getParentWriter()->getPhpWord()->getSettings();
  85. // Applies a language to a text run (defaults to 1036 : French (France))
  86. $langId = $docSettings->getThemeFontLang() != null && $docSettings->getThemeFontLang()->getLangId() != null ? $docSettings->getThemeFontLang()->getLangId() : 1036;
  87. $content = '';
  88. $content .= '\deftab720'; // Set the default tab size (720 twips)
  89. $content .= '\viewkind1'; // Set the view mode of the document
  90. $content .= '\uc1'; // Set the numberof bytes that follows a unicode character
  91. $content .= '\pard'; // Resets to default paragraph properties.
  92. $content .= '\nowidctlpar'; // No widow/orphan control
  93. $content .= '\lang' . $langId;
  94. $content .= '\kerning1'; // Point size (in half-points) above which to kern character pairs
  95. $content .= '\fs' . (Settings::getDefaultFontSize() * 2); // Set the font size in half-points
  96. if ($docSettings->hasEvenAndOddHeaders()) {
  97. $content .= '\\facingp';
  98. }
  99. $content .= PHP_EOL;
  100. return $content;
  101. }
  102. /**
  103. * Write titlepg directive if any "f" headers or footers
  104. *
  105. * @param \PhpOffice\PhpWord\Element\Section $section
  106. * @return string
  107. */
  108. private static function writeTitlepg($section)
  109. {
  110. foreach ($section->getHeaders() as $header) {
  111. if ($header->getType() === Footer::FIRST) {
  112. return '\\titlepg' . PHP_EOL;
  113. }
  114. }
  115. foreach ($section->getFooters() as $header) {
  116. if ($header->getType() === Footer::FIRST) {
  117. return '\\titlepg' . PHP_EOL;
  118. }
  119. }
  120. return '';
  121. }
  122. /**
  123. * Write sections
  124. *
  125. * @return string
  126. */
  127. private function writeSections()
  128. {
  129. $content = '';
  130. $sections = $this->getParentWriter()->getPhpWord()->getSections();
  131. $evenOdd = $this->getParentWriter()->getPhpWord()->getSettings()->hasEvenAndOddHeaders();
  132. foreach ($sections as $section) {
  133. $styleWriter = new SectionStyleWriter($section->getStyle());
  134. $styleWriter->setParentWriter($this->getParentWriter());
  135. $content .= $styleWriter->write();
  136. $content .= self::writeTitlepg($section);
  137. foreach ($section->getHeaders() as $header) {
  138. $type = $header->getType();
  139. if ($evenOdd || $type !== FOOTER::EVEN) {
  140. $content .= '{\\header';
  141. if ($type === Footer::FIRST) {
  142. $content .= 'f';
  143. } elseif ($evenOdd) {
  144. $content .= ($type === FOOTER::EVEN) ? 'l' : 'r';
  145. }
  146. foreach ($header->getElements() as $element) {
  147. $cl = get_class($element);
  148. $cl2 = str_replace('Element', 'Writer\\RTF\\Element', $cl);
  149. if (class_exists($cl2)) {
  150. $elementWriter = new $cl2($this->getParentWriter(), $element);
  151. $content .= $elementWriter->write();
  152. }
  153. }
  154. $content .= '}' . PHP_EOL;
  155. }
  156. }
  157. foreach ($section->getFooters() as $footer) {
  158. $type = $footer->getType();
  159. if ($evenOdd || $type !== FOOTER::EVEN) {
  160. $content .= '{\\footer';
  161. if ($type === Footer::FIRST) {
  162. $content .= 'f';
  163. } elseif ($evenOdd) {
  164. $content .= ($type === FOOTER::EVEN) ? 'l' : 'r';
  165. }
  166. foreach ($footer->getElements() as $element) {
  167. $cl = get_class($element);
  168. $cl2 = str_replace('Element', 'Writer\\RTF\\Element', $cl);
  169. if (class_exists($cl2)) {
  170. $elementWriter = new $cl2($this->getParentWriter(), $element);
  171. $content .= $elementWriter->write();
  172. }
  173. }
  174. $content .= '}' . PHP_EOL;
  175. }
  176. }
  177. $elementWriter = new Container($this->getParentWriter(), $section);
  178. $content .= $elementWriter->write();
  179. $content .= '\sect' . PHP_EOL;
  180. }
  181. return $content;
  182. }
  183. /**
  184. * Get date value
  185. *
  186. * The format of date value is `\yr?\mo?\dy?\hr?\min?\sec?`
  187. *
  188. * @param int $value
  189. * @return string
  190. */
  191. private function getDateValue($value)
  192. {
  193. $dateParts = array(
  194. 'Y' => 'yr',
  195. 'm' => 'mo',
  196. 'd' => 'dy',
  197. 'H' => 'hr',
  198. 'i' => 'min',
  199. 's' => 'sec',
  200. );
  201. $result = '';
  202. foreach ($dateParts as $dateFormat => $controlWord) {
  203. $result .= '\\' . $controlWord . date($dateFormat, $value);
  204. }
  205. return $result;
  206. }
  207. }