See Release Notes
Long Term Support Release
Differences Between: [Versions 310 and 401] [Versions 39 and 401]
1 <?php 2 3 namespace Box\Spout\Writer\ODS\Manager\Style; 4 5 use Box\Spout\Common\Entity\Style\BorderPart; 6 use Box\Spout\Common\Entity\Style\CellAlignment; 7 use Box\Spout\Writer\Common\Entity\Worksheet; 8 use Box\Spout\Writer\ODS\Helper\BorderHelper; 9 10 /** 11 * Class StyleManager 12 * Manages styles to be applied to a cell 13 */ 14 class StyleManager extends \Box\Spout\Writer\Common\Manager\Style\StyleManager 15 { 16 /** @var StyleRegistry */ 17 protected $styleRegistry; 18 19 /** 20 * Returns the content of the "styles.xml" file, given a list of styles. 21 * 22 * @param int $numWorksheets Number of worksheets created 23 * @return string 24 */ 25 public function getStylesXMLFileContent($numWorksheets) 26 { 27 $content = <<<'EOD' 28 <?xml version="1.0" encoding="UTF-8" standalone="yes"?> 29 <office:document-styles office:version="1.2" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0" xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" xmlns:msoxl="http://schemas.microsoft.com/office/excel/formula" xmlns:number="urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0" xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0" xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" xmlns:xlink="http://www.w3.org/1999/xlink"> 30 EOD; 31 32 $content .= $this->getFontFaceSectionContent(); 33 $content .= $this->getStylesSectionContent(); 34 $content .= $this->getAutomaticStylesSectionContent($numWorksheets); 35 $content .= $this->getMasterStylesSectionContent($numWorksheets); 36 37 $content .= <<<'EOD' 38 </office:document-styles> 39 EOD; 40 41 return $content; 42 } 43 44 /** 45 * Returns the content of the "<office:font-face-decls>" section, inside "styles.xml" file. 46 * 47 * @return string 48 */ 49 protected function getFontFaceSectionContent() 50 { 51 $content = '<office:font-face-decls>'; 52 foreach ($this->styleRegistry->getUsedFonts() as $fontName) { 53 $content .= '<style:font-face style:name="' . $fontName . '" svg:font-family="' . $fontName . '"/>'; 54 } 55 $content .= '</office:font-face-decls>'; 56 57 return $content; 58 } 59 60 /** 61 * Returns the content of the "<office:styles>" section, inside "styles.xml" file. 62 * 63 * @return string 64 */ 65 protected function getStylesSectionContent() 66 { 67 $defaultStyle = $this->getDefaultStyle(); 68 69 return <<<EOD 70 <office:styles> 71 <number:number-style style:name="N0"> 72 <number:number number:min-integer-digits="1"/> 73 </number:number-style> 74 <style:style style:data-style-name="N0" style:family="table-cell" style:name="Default"> 75 <style:table-cell-properties fo:background-color="transparent" style:vertical-align="automatic"/> 76 <style:text-properties fo:color="#{$defaultStyle->getFontColor()}" 77 fo:font-size="{$defaultStyle->getFontSize()}pt" style:font-size-asian="{$defaultStyle->getFontSize()}pt" style:font-size-complex="{$defaultStyle->getFontSize()}pt" 78 style:font-name="{$defaultStyle->getFontName()}" style:font-name-asian="{$defaultStyle->getFontName()}" style:font-name-complex="{$defaultStyle->getFontName()}"/> 79 </style:style> 80 </office:styles> 81 EOD; 82 } 83 84 /** 85 * Returns the content of the "<office:automatic-styles>" section, inside "styles.xml" file. 86 * 87 * @param int $numWorksheets Number of worksheets created 88 * @return string 89 */ 90 protected function getAutomaticStylesSectionContent($numWorksheets) 91 { 92 $content = '<office:automatic-styles>'; 93 94 for ($i = 1; $i <= $numWorksheets; $i++) { 95 $content .= <<<EOD 96 <style:page-layout style:name="pm$i"> 97 <style:page-layout-properties style:first-page-number="continue" style:print="objects charts drawings" style:table-centering="none"/> 98 <style:header-style/> 99 <style:footer-style/> 100 </style:page-layout> 101 EOD; 102 } 103 104 $content .= '</office:automatic-styles>'; 105 106 return $content; 107 } 108 109 /** 110 * Returns the content of the "<office:master-styles>" section, inside "styles.xml" file. 111 * 112 * @param int $numWorksheets Number of worksheets created 113 * @return string 114 */ 115 protected function getMasterStylesSectionContent($numWorksheets) 116 { 117 $content = '<office:master-styles>'; 118 119 for ($i = 1; $i <= $numWorksheets; $i++) { 120 $content .= <<<EOD 121 <style:master-page style:name="mp$i" style:page-layout-name="pm$i"> 122 <style:header/> 123 <style:header-left style:display="false"/> 124 <style:footer/> 125 <style:footer-left style:display="false"/> 126 </style:master-page> 127 EOD; 128 } 129 130 $content .= '</office:master-styles>'; 131 132 return $content; 133 } 134 135 /** 136 * Returns the contents of the "<office:font-face-decls>" section, inside "content.xml" file. 137 * 138 * @return string 139 */ 140 public function getContentXmlFontFaceSectionContent() 141 { 142 $content = '<office:font-face-decls>'; 143 foreach ($this->styleRegistry->getUsedFonts() as $fontName) { 144 $content .= '<style:font-face style:name="' . $fontName . '" svg:font-family="' . $fontName . '"/>'; 145 } 146 $content .= '</office:font-face-decls>'; 147 148 return $content; 149 } 150 151 /** 152 * Returns the contents of the "<office:automatic-styles>" section, inside "content.xml" file. 153 * 154 * @param Worksheet[] $worksheets 155 * @return string 156 */ 157 public function getContentXmlAutomaticStylesSectionContent($worksheets) 158 { 159 $content = '<office:automatic-styles>'; 160 161 foreach ($this->styleRegistry->getRegisteredStyles() as $style) { 162 $content .= $this->getStyleSectionContent($style); 163 } 164 165 $content .= <<<'EOD' 166 <style:style style:family="table-column" style:name="co1"> 167 <style:table-column-properties fo:break-before="auto"/> 168 </style:style> 169 <style:style style:family="table-row" style:name="ro1"> 170 <style:table-row-properties fo:break-before="auto" style:row-height="15pt" style:use-optimal-row-height="true"/> 171 </style:style> 172 EOD; 173 174 foreach ($worksheets as $worksheet) { 175 $worksheetId = $worksheet->getId(); 176 $isSheetVisible = $worksheet->getExternalSheet()->isVisible() ? 'true' : 'false'; 177 178 $content .= <<<EOD 179 <style:style style:family="table" style:master-page-name="mp$worksheetId" style:name="ta$worksheetId"> 180 <style:table-properties style:writing-mode="lr-tb" table:display="$isSheetVisible"/> 181 </style:style> 182 EOD; 183 } 184 185 $content .= '</office:automatic-styles>'; 186 187 return $content; 188 } 189 190 /** 191 * Returns the contents of the "<style:style>" section, inside "<office:automatic-styles>" section 192 * 193 * @param \Box\Spout\Common\Entity\Style\Style $style 194 * @return string 195 */ 196 protected function getStyleSectionContent($style) 197 { 198 $styleIndex = $style->getId() + 1; // 1-based 199 200 $content = '<style:style style:data-style-name="N0" style:family="table-cell" style:name="ce' . $styleIndex . '" style:parent-style-name="Default">'; 201 202 $content .= $this->getTextPropertiesSectionContent($style); 203 $content .= $this->getParagraphPropertiesSectionContent($style); 204 $content .= $this->getTableCellPropertiesSectionContent($style); 205 206 $content .= '</style:style>'; 207 208 return $content; 209 } 210 211 /** 212 * Returns the contents of the "<style:text-properties>" section, inside "<style:style>" section 213 * 214 * @param \Box\Spout\Common\Entity\Style\Style $style 215 * @return string 216 */ 217 private function getTextPropertiesSectionContent($style) 218 { 219 if (!$style->shouldApplyFont()) { 220 return ''; 221 } 222 223 return '<style:text-properties ' 224 . $this->getFontSectionContent($style) 225 . '/>'; 226 } 227 228 /** 229 * Returns the contents of the fonts definition section, inside "<style:text-properties>" section 230 * 231 * @param \Box\Spout\Common\Entity\Style\Style $style 232 * 233 * @return string 234 */ 235 private function getFontSectionContent($style) 236 { 237 $defaultStyle = $this->getDefaultStyle(); 238 $content = ''; 239 240 $fontColor = $style->getFontColor(); 241 if ($fontColor !== $defaultStyle->getFontColor()) { 242 $content .= ' fo:color="#' . $fontColor . '"'; 243 } 244 245 $fontName = $style->getFontName(); 246 if ($fontName !== $defaultStyle->getFontName()) { 247 $content .= ' style:font-name="' . $fontName . '" style:font-name-asian="' . $fontName . '" style:font-name-complex="' . $fontName . '"'; 248 } 249 250 $fontSize = $style->getFontSize(); 251 if ($fontSize !== $defaultStyle->getFontSize()) { 252 $content .= ' fo:font-size="' . $fontSize . 'pt" style:font-size-asian="' . $fontSize . 'pt" style:font-size-complex="' . $fontSize . 'pt"'; 253 } 254 255 if ($style->isFontBold()) { 256 $content .= ' fo:font-weight="bold" style:font-weight-asian="bold" style:font-weight-complex="bold"'; 257 } 258 if ($style->isFontItalic()) { 259 $content .= ' fo:font-style="italic" style:font-style-asian="italic" style:font-style-complex="italic"'; 260 } 261 if ($style->isFontUnderline()) { 262 $content .= ' style:text-underline-style="solid" style:text-underline-type="single"'; 263 } 264 if ($style->isFontStrikethrough()) { 265 $content .= ' style:text-line-through-style="solid"'; 266 } 267 268 return $content; 269 } 270 271 /** 272 * Returns the contents of the "<style:paragraph-properties>" section, inside "<style:style>" section 273 * 274 * @param \Box\Spout\Common\Entity\Style\Style $style 275 * 276 * @return string 277 */ 278 private function getParagraphPropertiesSectionContent($style) 279 { 280 if (!$style->shouldApplyCellAlignment()) { 281 return ''; 282 } 283 284 return '<style:paragraph-properties ' 285 . $this->getCellAlignmentSectionContent($style) 286 . '/>'; 287 } 288 289 /** 290 * Returns the contents of the cell alignment definition for the "<style:paragraph-properties>" section 291 * 292 * @param \Box\Spout\Common\Entity\Style\Style $style 293 * 294 * @return string 295 */ 296 private function getCellAlignmentSectionContent($style) 297 { 298 return \sprintf( 299 ' fo:text-align="%s" ', 300 $this->transformCellAlignment($style->getCellAlignment()) 301 ); 302 } 303 304 /** 305 * Even though "left" and "right" alignments are part of the spec, and interpreted 306 * respectively as "start" and "end", using the recommended values increase compatibility 307 * with software that will read the created ODS file. 308 * 309 * @param string $cellAlignment 310 * 311 * @return string 312 */ 313 private function transformCellAlignment($cellAlignment) 314 { 315 switch ($cellAlignment) { 316 case CellAlignment::LEFT: return 'start'; 317 case CellAlignment::RIGHT: return 'end'; 318 default: return $cellAlignment; 319 } 320 } 321 322 /** 323 * Returns the contents of the "<style:table-cell-properties>" section, inside "<style:style>" section 324 * 325 * @param \Box\Spout\Common\Entity\Style\Style $style 326 * @return string 327 */ 328 private function getTableCellPropertiesSectionContent($style) 329 { 330 $content = '<style:table-cell-properties '; 331 332 if ($style->shouldWrapText()) { 333 $content .= $this->getWrapTextXMLContent(); 334 } 335 336 if ($style->shouldApplyBorder()) { 337 $content .= $this->getBorderXMLContent($style); 338 } 339 340 if ($style->shouldApplyBackgroundColor()) { 341 $content .= $this->getBackgroundColorXMLContent($style); 342 } 343 344 $content .= '/>'; 345 346 return $content; 347 } 348 349 /** 350 * Returns the contents of the wrap text definition for the "<style:table-cell-properties>" section 351 * 352 * @return string 353 */ 354 private function getWrapTextXMLContent() 355 { 356 return ' fo:wrap-option="wrap" style:vertical-align="automatic" '; 357 } 358 359 /** 360 * Returns the contents of the borders definition for the "<style:table-cell-properties>" section 361 * 362 * @param \Box\Spout\Common\Entity\Style\Style $style 363 * @return string 364 */ 365 private function getBorderXMLContent($style) 366 { 367 $borders = \array_map(function (BorderPart $borderPart) { 368 return BorderHelper::serializeBorderPart($borderPart); 369 }, $style->getBorder()->getParts()); 370 371 return \sprintf(' %s ', \implode(' ', $borders)); 372 } 373 374 /** 375 * Returns the contents of the background color definition for the "<style:table-cell-properties>" section 376 * 377 * @param \Box\Spout\Common\Entity\Style\Style $style 378 * @return string 379 */ 380 private function getBackgroundColorXMLContent($style) 381 { 382 return \sprintf(' fo:background-color="#%s" ', $style->getBackgroundColor()); 383 } 384 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body