See Release Notes
Long Term Support Release
Differences Between: [Versions 39 and 311] [Versions 39 and 400] [Versions 39 and 401]
1 <?php 2 3 namespace Box\Spout\Writer\XLSX\Manager\Style; 4 5 use Box\Spout\Common\Entity\Style\Color; 6 use Box\Spout\Common\Entity\Style\Style; 7 use Box\Spout\Writer\XLSX\Helper\BorderHelper; 8 9 /** 10 * Class StyleManager 11 * Manages styles to be applied to a cell 12 */ 13 class StyleManager extends \Box\Spout\Writer\Common\Manager\Style\StyleManager 14 { 15 /** @var StyleRegistry */ 16 protected $styleRegistry; 17 18 /** 19 * For empty cells, we can specify a style or not. If no style are specified, 20 * then the software default will be applied. But sometimes, it may be useful 21 * to override this default style, for instance if the cell should have a 22 * background color different than the default one or some borders 23 * (fonts property don't really matter here). 24 * 25 * @param int $styleId 26 * @return bool Whether the cell should define a custom style 27 */ 28 public function shouldApplyStyleOnEmptyCell($styleId) 29 { 30 $associatedFillId = $this->styleRegistry->getFillIdForStyleId($styleId); 31 $hasStyleCustomFill = ($associatedFillId !== null && $associatedFillId !== 0); 32 33 $associatedBorderId = $this->styleRegistry->getBorderIdForStyleId($styleId); 34 $hasStyleCustomBorders = ($associatedBorderId !== null && $associatedBorderId !== 0); 35 36 return ($hasStyleCustomFill || $hasStyleCustomBorders); 37 } 38 39 /** 40 * Returns the content of the "styles.xml" file, given a list of styles. 41 * 42 * @return string 43 */ 44 public function getStylesXMLFileContent() 45 { 46 $content = <<<'EOD' 47 <?xml version="1.0" encoding="UTF-8" standalone="yes"?> 48 <styleSheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main"> 49 EOD; 50 51 $content .= $this->getFontsSectionContent(); 52 $content .= $this->getFillsSectionContent(); 53 $content .= $this->getBordersSectionContent(); 54 $content .= $this->getCellStyleXfsSectionContent(); 55 $content .= $this->getCellXfsSectionContent(); 56 $content .= $this->getCellStylesSectionContent(); 57 58 $content .= <<<'EOD' 59 </styleSheet> 60 EOD; 61 62 return $content; 63 } 64 65 /** 66 * Returns the content of the "<fonts>" section. 67 * 68 * @return string 69 */ 70 protected function getFontsSectionContent() 71 { 72 $registeredStyles = $this->styleRegistry->getRegisteredStyles(); 73 74 $content = '<fonts count="' . count($registeredStyles) . '">'; 75 76 /** @var Style $style */ 77 foreach ($registeredStyles as $style) { 78 $content .= '<font>'; 79 80 $content .= '<sz val="' . $style->getFontSize() . '"/>'; 81 $content .= '<color rgb="' . Color::toARGB($style->getFontColor()) . '"/>'; 82 $content .= '<name val="' . $style->getFontName() . '"/>'; 83 84 if ($style->isFontBold()) { 85 $content .= '<b/>'; 86 } 87 if ($style->isFontItalic()) { 88 $content .= '<i/>'; 89 } 90 if ($style->isFontUnderline()) { 91 $content .= '<u/>'; 92 } 93 if ($style->isFontStrikethrough()) { 94 $content .= '<strike/>'; 95 } 96 97 $content .= '</font>'; 98 } 99 100 $content .= '</fonts>'; 101 102 return $content; 103 } 104 105 /** 106 * Returns the content of the "<fills>" section. 107 * 108 * @return string 109 */ 110 protected function getFillsSectionContent() 111 { 112 $registeredFills = $this->styleRegistry->getRegisteredFills(); 113 114 // Excel reserves two default fills 115 $fillsCount = count($registeredFills) + 2; 116 $content = sprintf('<fills count="%d">', $fillsCount); 117 118 $content .= '<fill><patternFill patternType="none"/></fill>'; 119 $content .= '<fill><patternFill patternType="gray125"/></fill>'; 120 121 // The other fills are actually registered by setting a background color 122 foreach ($registeredFills as $styleId) { 123 /** @var Style $style */ 124 $style = $this->styleRegistry->getStyleFromStyleId($styleId); 125 126 $backgroundColor = $style->getBackgroundColor(); 127 $content .= sprintf( 128 '<fill><patternFill patternType="solid"><fgColor rgb="%s"/></patternFill></fill>', 129 $backgroundColor 130 ); 131 } 132 133 $content .= '</fills>'; 134 135 return $content; 136 } 137 138 /** 139 * Returns the content of the "<borders>" section. 140 * 141 * @return string 142 */ 143 protected function getBordersSectionContent() 144 { 145 $registeredBorders = $this->styleRegistry->getRegisteredBorders(); 146 147 // There is one default border with index 0 148 $borderCount = count($registeredBorders) + 1; 149 150 $content = '<borders count="' . $borderCount . '">'; 151 152 // Default border starting at index 0 153 $content .= '<border><left/><right/><top/><bottom/></border>'; 154 155 foreach ($registeredBorders as $styleId) { 156 /** @var \Box\Spout\Common\Entity\Style\Style $style */ 157 $style = $this->styleRegistry->getStyleFromStyleId($styleId); 158 $border = $style->getBorder(); 159 $content .= '<border>'; 160 161 // @link https://github.com/box/spout/issues/271 162 $sortOrder = ['left', 'right', 'top', 'bottom']; 163 164 foreach ($sortOrder as $partName) { 165 if ($border->hasPart($partName)) { 166 /** @var $part \Box\Spout\Common\Entity\Style\BorderPart */ 167 $part = $border->getPart($partName); 168 $content .= BorderHelper::serializeBorderPart($part); 169 } 170 } 171 172 $content .= '</border>'; 173 } 174 175 $content .= '</borders>'; 176 177 return $content; 178 } 179 180 /** 181 * Returns the content of the "<cellStyleXfs>" section. 182 * 183 * @return string 184 */ 185 protected function getCellStyleXfsSectionContent() 186 { 187 return <<<'EOD' 188 <cellStyleXfs count="1"> 189 <xf borderId="0" fillId="0" fontId="0" numFmtId="0"/> 190 </cellStyleXfs> 191 EOD; 192 } 193 194 /** 195 * Returns the content of the "<cellXfs>" section. 196 * 197 * @return string 198 */ 199 protected function getCellXfsSectionContent() 200 { 201 $registeredStyles = $this->styleRegistry->getRegisteredStyles(); 202 203 $content = '<cellXfs count="' . count($registeredStyles) . '">'; 204 205 foreach ($registeredStyles as $style) { 206 $styleId = $style->getId(); 207 $fillId = $this->getFillIdForStyleId($styleId); 208 $borderId = $this->getBorderIdForStyleId($styleId); 209 210 $content .= '<xf numFmtId="0" fontId="' . $styleId . '" fillId="' . $fillId . '" borderId="' . $borderId . '" xfId="0"'; 211 212 if ($style->shouldApplyFont()) { 213 $content .= ' applyFont="1"'; 214 } 215 216 $content .= sprintf(' applyBorder="%d"', $style->shouldApplyBorder() ? 1 : 0); 217 218 if ($style->shouldWrapText()) { 219 $content .= ' applyAlignment="1">'; 220 $content .= '<alignment wrapText="1"/>'; 221 $content .= '</xf>'; 222 } else { 223 $content .= '/>'; 224 } 225 } 226 227 $content .= '</cellXfs>'; 228 229 return $content; 230 } 231 232 /** 233 * Returns the fill ID associated to the given style ID. 234 * For the default style, we don't a fill. 235 * 236 * @param int $styleId 237 * @return int 238 */ 239 private function getFillIdForStyleId($styleId) 240 { 241 // For the default style (ID = 0), we don't want to override the fill. 242 // Otherwise all cells of the spreadsheet will have a background color. 243 $isDefaultStyle = ($styleId === 0); 244 245 return $isDefaultStyle ? 0 : ($this->styleRegistry->getFillIdForStyleId($styleId) ?: 0); 246 } 247 248 /** 249 * Returns the fill ID associated to the given style ID. 250 * For the default style, we don't a border. 251 * 252 * @param int $styleId 253 * @return int 254 */ 255 private function getBorderIdForStyleId($styleId) 256 { 257 // For the default style (ID = 0), we don't want to override the border. 258 // Otherwise all cells of the spreadsheet will have a border. 259 $isDefaultStyle = ($styleId === 0); 260 261 return $isDefaultStyle ? 0 : ($this->styleRegistry->getBorderIdForStyleId($styleId) ?: 0); 262 } 263 264 /** 265 * Returns the content of the "<cellStyles>" section. 266 * 267 * @return string 268 */ 269 protected function getCellStylesSectionContent() 270 { 271 return <<<'EOD' 272 <cellStyles count="1"> 273 <cellStyle builtinId="0" name="Normal" xfId="0"/> 274 </cellStyles> 275 EOD; 276 } 277 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body