Search moodle.org's
Developer Documentation

See Release Notes
Long Term Support Release

  • Bug fixes for general core bugs in 3.9.x will end* 10 May 2021 (12 months).
  • Bug fixes for security issues in 3.9.x will end* 8 May 2023 (36 months).
  • PHP version: minimum PHP 7.2.0 Note: minimum PHP version has increased since Moodle 3.8. PHP 7.3.x and 7.4.x are supported too.

Differences Between: [Versions 39 and 311] [Versions 39 and 400] [Versions 39 and 401] [Versions 39 and 402] [Versions 39 and 403]

   1  <?php
   2  
   3  namespace PhpOffice\PhpSpreadsheet\Reader\Xlsx;
   4  
   5  use PhpOffice\PhpSpreadsheet\Style\Alignment;
   6  use PhpOffice\PhpSpreadsheet\Style\Border;
   7  use PhpOffice\PhpSpreadsheet\Style\Borders;
   8  use PhpOffice\PhpSpreadsheet\Style\Color;
   9  use PhpOffice\PhpSpreadsheet\Style\Fill;
  10  use PhpOffice\PhpSpreadsheet\Style\Font;
  11  use PhpOffice\PhpSpreadsheet\Style\Protection;
  12  use PhpOffice\PhpSpreadsheet\Style\Style;
  13  
  14  class Styles extends BaseParserClass
  15  {
  16      /**
  17       * Theme instance.
  18       *
  19       * @var Theme
  20       */
  21      private static $theme = null;
  22  
  23      private $styles = [];
  24  
  25      private $cellStyles = [];
  26  
  27      private $styleXml;
  28  
  29      public function __construct(\SimpleXMLElement $styleXml)
  30      {
  31          $this->styleXml = $styleXml;
  32      }
  33  
  34      public function setStyleBaseData(Theme $theme = null, $styles = [], $cellStyles = [])
  35      {
  36          self::$theme = $theme;
  37          $this->styles = $styles;
  38          $this->cellStyles = $cellStyles;
  39      }
  40  
  41      private static function readFontStyle(Font $fontStyle, \SimpleXMLElement $fontStyleXml)
  42      {
  43          $fontStyle->setName((string) $fontStyleXml->name['val']);
  44          $fontStyle->setSize((float) $fontStyleXml->sz['val']);
  45  
  46          if (isset($fontStyleXml->b)) {
  47              $fontStyle->setBold(!isset($fontStyleXml->b['val']) || self::boolean((string) $fontStyleXml->b['val']));
  48          }
  49          if (isset($fontStyleXml->i)) {
  50              $fontStyle->setItalic(!isset($fontStyleXml->i['val']) || self::boolean((string) $fontStyleXml->i['val']));
  51          }
  52          if (isset($fontStyleXml->strike)) {
  53              $fontStyle->setStrikethrough(!isset($fontStyleXml->strike['val']) || self::boolean((string) $fontStyleXml->strike['val']));
  54          }
  55          $fontStyle->getColor()->setARGB(self::readColor($fontStyleXml->color));
  56  
  57          if (isset($fontStyleXml->u) && !isset($fontStyleXml->u['val'])) {
  58              $fontStyle->setUnderline(Font::UNDERLINE_SINGLE);
  59          } elseif (isset($fontStyleXml->u, $fontStyleXml->u['val'])) {
  60              $fontStyle->setUnderline((string) $fontStyleXml->u['val']);
  61          }
  62  
  63          if (isset($fontStyleXml->vertAlign, $fontStyleXml->vertAlign['val'])) {
  64              $verticalAlign = strtolower((string) $fontStyleXml->vertAlign['val']);
  65              if ($verticalAlign === 'superscript') {
  66                  $fontStyle->setSuperscript(true);
  67              }
  68              if ($verticalAlign === 'subscript') {
  69                  $fontStyle->setSubscript(true);
  70              }
  71          }
  72      }
  73  
  74      private static function readFillStyle(Fill $fillStyle, \SimpleXMLElement $fillStyleXml)
  75      {
  76          if ($fillStyleXml->gradientFill) {
  77              /** @var \SimpleXMLElement $gradientFill */
  78              $gradientFill = $fillStyleXml->gradientFill[0];
  79              if (!empty($gradientFill['type'])) {
  80                  $fillStyle->setFillType((string) $gradientFill['type']);
  81              }
  82              $fillStyle->setRotation((float) ($gradientFill['degree']));
  83              $gradientFill->registerXPathNamespace('sml', 'http://schemas.openxmlformats.org/spreadsheetml/2006/main');
  84              $fillStyle->getStartColor()->setARGB(self::readColor(self::getArrayItem($gradientFill->xpath('sml:stop[@position=0]'))->color));
  85              $fillStyle->getEndColor()->setARGB(self::readColor(self::getArrayItem($gradientFill->xpath('sml:stop[@position=1]'))->color));
  86          } elseif ($fillStyleXml->patternFill) {
  87              $patternType = (string) $fillStyleXml->patternFill['patternType'] != '' ? (string) $fillStyleXml->patternFill['patternType'] : 'solid';
  88              $fillStyle->setFillType($patternType);
  89              if ($fillStyleXml->patternFill->fgColor) {
  90                  $fillStyle->getStartColor()->setARGB(self::readColor($fillStyleXml->patternFill->fgColor, true));
  91              } else {
  92                  $fillStyle->getStartColor()->setARGB('FF000000');
  93              }
  94              if ($fillStyleXml->patternFill->bgColor) {
  95                  $fillStyle->getEndColor()->setARGB(self::readColor($fillStyleXml->patternFill->bgColor, true));
  96              }
  97          }
  98      }
  99  
 100      private static function readBorderStyle(Borders $borderStyle, \SimpleXMLElement $borderStyleXml)
 101      {
 102          $diagonalUp = self::boolean((string) $borderStyleXml['diagonalUp']);
 103          $diagonalDown = self::boolean((string) $borderStyleXml['diagonalDown']);
 104          if (!$diagonalUp && !$diagonalDown) {
 105              $borderStyle->setDiagonalDirection(Borders::DIAGONAL_NONE);
 106          } elseif ($diagonalUp && !$diagonalDown) {
 107              $borderStyle->setDiagonalDirection(Borders::DIAGONAL_UP);
 108          } elseif (!$diagonalUp && $diagonalDown) {
 109              $borderStyle->setDiagonalDirection(Borders::DIAGONAL_DOWN);
 110          } else {
 111              $borderStyle->setDiagonalDirection(Borders::DIAGONAL_BOTH);
 112          }
 113  
 114          self::readBorder($borderStyle->getLeft(), $borderStyleXml->left);
 115          self::readBorder($borderStyle->getRight(), $borderStyleXml->right);
 116          self::readBorder($borderStyle->getTop(), $borderStyleXml->top);
 117          self::readBorder($borderStyle->getBottom(), $borderStyleXml->bottom);
 118          self::readBorder($borderStyle->getDiagonal(), $borderStyleXml->diagonal);
 119      }
 120  
 121      private static function readBorder(Border $border, \SimpleXMLElement $borderXml)
 122      {
 123          if (isset($borderXml['style'])) {
 124              $border->setBorderStyle((string) $borderXml['style']);
 125          }
 126          if (isset($borderXml->color)) {
 127              $border->getColor()->setARGB(self::readColor($borderXml->color));
 128          }
 129      }
 130  
 131      private static function readAlignmentStyle(Alignment $alignment, \SimpleXMLElement $alignmentXml)
 132      {
 133          $alignment->setHorizontal((string) $alignmentXml->alignment['horizontal']);
 134          $alignment->setVertical((string) $alignmentXml->alignment['vertical']);
 135  
 136          $textRotation = 0;
 137          if ((int) $alignmentXml->alignment['textRotation'] <= 90) {
 138              $textRotation = (int) $alignmentXml->alignment['textRotation'];
 139          } elseif ((int) $alignmentXml->alignment['textRotation'] > 90) {
 140              $textRotation = 90 - (int) $alignmentXml->alignment['textRotation'];
 141          }
 142  
 143          $alignment->setTextRotation((int) $textRotation);
 144          $alignment->setWrapText(self::boolean((string) $alignmentXml->alignment['wrapText']));
 145          $alignment->setShrinkToFit(self::boolean((string) $alignmentXml->alignment['shrinkToFit']));
 146          $alignment->setIndent((int) ((string) $alignmentXml->alignment['indent']) > 0 ? (int) ((string) $alignmentXml->alignment['indent']) : 0);
 147          $alignment->setReadOrder((int) ((string) $alignmentXml->alignment['readingOrder']) > 0 ? (int) ((string) $alignmentXml->alignment['readingOrder']) : 0);
 148      }
 149  
 150      private function readStyle(Style $docStyle, $style)
 151      {
 152          $docStyle->getNumberFormat()->setFormatCode($style->numFmt);
 153  
 154          if (isset($style->font)) {
 155              self::readFontStyle($docStyle->getFont(), $style->font);
 156          }
 157  
 158          if (isset($style->fill)) {
 159              self::readFillStyle($docStyle->getFill(), $style->fill);
 160          }
 161  
 162          if (isset($style->border)) {
 163              self::readBorderStyle($docStyle->getBorders(), $style->border);
 164          }
 165  
 166          if (isset($style->alignment->alignment)) {
 167              self::readAlignmentStyle($docStyle->getAlignment(), $style->alignment);
 168          }
 169  
 170          // protection
 171          if (isset($style->protection)) {
 172              $this->readProtectionLocked($docStyle, $style);
 173              $this->readProtectionHidden($docStyle, $style);
 174          }
 175  
 176          // top-level style settings
 177          if (isset($style->quotePrefix)) {
 178              $docStyle->setQuotePrefix(true);
 179          }
 180      }
 181  
 182      private function readProtectionLocked(Style $docStyle, $style)
 183      {
 184          if (isset($style->protection['locked'])) {
 185              if (self::boolean((string) $style->protection['locked'])) {
 186                  $docStyle->getProtection()->setLocked(Protection::PROTECTION_PROTECTED);
 187              } else {
 188                  $docStyle->getProtection()->setLocked(Protection::PROTECTION_UNPROTECTED);
 189              }
 190          }
 191      }
 192  
 193      private function readProtectionHidden(Style $docStyle, $style)
 194      {
 195          if (isset($style->protection['hidden'])) {
 196              if (self::boolean((string) $style->protection['hidden'])) {
 197                  $docStyle->getProtection()->setHidden(Protection::PROTECTION_PROTECTED);
 198              } else {
 199                  $docStyle->getProtection()->setHidden(Protection::PROTECTION_UNPROTECTED);
 200              }
 201          }
 202      }
 203  
 204      private static function readColor($color, $background = false)
 205      {
 206          if (isset($color['rgb'])) {
 207              return (string) $color['rgb'];
 208          } elseif (isset($color['indexed'])) {
 209              return Color::indexedColor($color['indexed'] - 7, $background)->getARGB();
 210          } elseif (isset($color['theme'])) {
 211              if (self::$theme !== null) {
 212                  $returnColour = self::$theme->getColourByIndex((int) $color['theme']);
 213                  if (isset($color['tint'])) {
 214                      $tintAdjust = (float) $color['tint'];
 215                      $returnColour = Color::changeBrightness($returnColour, $tintAdjust);
 216                  }
 217  
 218                  return 'FF' . $returnColour;
 219              }
 220          }
 221  
 222          return ($background) ? 'FFFFFFFF' : 'FF000000';
 223      }
 224  
 225      public function dxfs($readDataOnly = false)
 226      {
 227          $dxfs = [];
 228          if (!$readDataOnly && $this->styleXml) {
 229              //    Conditional Styles
 230              if ($this->styleXml->dxfs) {
 231                  foreach ($this->styleXml->dxfs->dxf as $dxf) {
 232                      $style = new Style(false, true);
 233                      $this->readStyle($style, $dxf);
 234                      $dxfs[] = $style;
 235                  }
 236              }
 237              //    Cell Styles
 238              if ($this->styleXml->cellStyles) {
 239                  foreach ($this->styleXml->cellStyles->cellStyle as $cellStyle) {
 240                      if ((int) ($cellStyle['builtinId']) == 0) {
 241                          if (isset($this->cellStyles[(int) ($cellStyle['xfId'])])) {
 242                              // Set default style
 243                              $style = new Style();
 244                              $this->readStyle($style, $this->cellStyles[(int) ($cellStyle['xfId'])]);
 245  
 246                              // normal style, currently not using it for anything
 247                          }
 248                      }
 249                  }
 250              }
 251          }
 252  
 253          return $dxfs;
 254      }
 255  
 256      public function styles()
 257      {
 258          return $this->styles;
 259      }
 260  
 261      private static function getArrayItem($array, $key = 0)
 262      {
 263          return $array[$key] ?? null;
 264      }
 265  }