Search moodle.org's
Developer Documentation

See Release Notes
Long Term Support Release

  • Bug fixes for general core bugs in 4.1.x will end 13 November 2023 (12 months).
  • Bug fixes for security issues in 4.1.x will end 10 November 2025 (36 months).
  • PHP version: minimum PHP 7.4.0 Note: minimum PHP version has increased since Moodle 4.0. PHP 8.0.x is supported too.

Differences Between: [Versions 310 and 401] [Versions 39 and 401]

   1  <?php
   2  
   3  namespace Box\Spout\Writer\XLSX\Manager\Style;
   4  
   5  use Box\Spout\Common\Entity\Style\Style;
   6  
   7  /**
   8   * Class StyleRegistry
   9   * Registry for all used styles
  10   */
  11  class StyleRegistry extends \Box\Spout\Writer\Common\Manager\Style\StyleRegistry
  12  {
  13      /**
  14       * @see https://msdn.microsoft.com/en-us/library/ff529597(v=office.12).aspx
  15       * @var array Mapping between built-in format and the associated numFmtId
  16       */
  17      protected static $builtinNumFormatToIdMapping = [
  18          'General' => 0,
  19          '0' => 1,
  20          '0.00' => 2,
  21          '#,##0' => 3,
  22          '#,##0.00' => 4,
  23          '$#,##0,\-$#,##0' => 5,
  24          '$#,##0,[Red]\-$#,##0' => 6,
  25          '$#,##0.00,\-$#,##0.00' => 7,
  26          '$#,##0.00,[Red]\-$#,##0.00' => 8,
  27          '0%' => 9,
  28          '0.00%' => 10,
  29          '0.00E+00' => 11,
  30          '# ?/?' => 12,
  31          '# ??/??' => 13,
  32          'mm-dd-yy' => 14,
  33          'd-mmm-yy' => 15,
  34          'd-mmm' => 16,
  35          'mmm-yy' => 17,
  36          'h:mm AM/PM' => 18,
  37          'h:mm:ss AM/PM' => 19,
  38          'h:mm' => 20,
  39          'h:mm:ss' => 21,
  40          'm/d/yy h:mm' => 22,
  41  
  42          '#,##0 ,(#,##0)' => 37,
  43          '#,##0 ,[Red](#,##0)' => 38,
  44          '#,##0.00,(#,##0.00)' => 39,
  45          '#,##0.00,[Red](#,##0.00)' => 40,
  46  
  47          '_("$"* #,##0.00_),_("$"* \(#,##0.00\),_("$"* "-"??_),_(@_)' => 44,
  48          'mm:ss' => 45,
  49          '[h]:mm:ss' => 46,
  50          'mm:ss.0' => 47,
  51  
  52          '##0.0E+0' => 48,
  53          '@' => 49,
  54  
  55          '[$-404]e/m/d' => 27,
  56          'm/d/yy' => 30,
  57          't0' => 59,
  58          't0.00' => 60,
  59          't#,##0' => 61,
  60          't#,##0.00' => 62,
  61          't0%' => 67,
  62          't0.00%' => 68,
  63          't# ?/?' => 69,
  64          't# ??/??' => 70,
  65      ];
  66  
  67      /**
  68       * @var array
  69       */
  70      protected $registeredFormats = [];
  71  
  72      /**
  73       * @var array [STYLE_ID] => [FORMAT_ID] maps a style to a format declaration
  74       */
  75      protected $styleIdToFormatsMappingTable = [];
  76  
  77      /**
  78       * If the numFmtId is lower than 0xA4 (164 in decimal)
  79       * then it's a built-in number format.
  80       * Since Excel is the dominant vendor - we play along here
  81       *
  82       * @var int The fill index counter for custom fills.
  83       */
  84      protected $formatIndex = 164;
  85  
  86      /**
  87       * @var array
  88       */
  89      protected $registeredFills = [];
  90  
  91      /**
  92       * @var array [STYLE_ID] => [FILL_ID] maps a style to a fill declaration
  93       */
  94      protected $styleIdToFillMappingTable = [];
  95  
  96      /**
  97       * Excel preserves two default fills with index 0 and 1
  98       * Since Excel is the dominant vendor - we play along here
  99       *
 100       * @var int The fill index counter for custom fills.
 101       */
 102      protected $fillIndex = 2;
 103  
 104      /**
 105       * @var array
 106       */
 107      protected $registeredBorders = [];
 108  
 109      /**
 110       * @var array [STYLE_ID] => [BORDER_ID] maps a style to a border declaration
 111       */
 112      protected $styleIdToBorderMappingTable = [];
 113  
 114      /**
 115       * XLSX specific operations on the registered styles
 116       *
 117       * @param Style $style
 118       * @return Style
 119       */
 120      public function registerStyle(Style $style)
 121      {
 122          if ($style->isRegistered()) {
 123              return $style;
 124          }
 125  
 126          $registeredStyle = parent::registerStyle($style);
 127          $this->registerFill($registeredStyle);
 128          $this->registerFormat($registeredStyle);
 129          $this->registerBorder($registeredStyle);
 130  
 131          return $registeredStyle;
 132      }
 133  
 134      /**
 135       * Register a format definition
 136       *
 137       * @param Style $style
 138       */
 139      protected function registerFormat(Style $style)
 140      {
 141          $styleId = $style->getId();
 142  
 143          $format = $style->getFormat();
 144          if ($format) {
 145              $isFormatRegistered = isset($this->registeredFormats[$format]);
 146  
 147              // We need to track the already registered format definitions
 148              if ($isFormatRegistered) {
 149                  $registeredStyleId = $this->registeredFormats[$format];
 150                  $registeredFormatId = $this->styleIdToFormatsMappingTable[$registeredStyleId];
 151                  $this->styleIdToFormatsMappingTable[$styleId] = $registeredFormatId;
 152              } else {
 153                  $this->registeredFormats[$format] = $styleId;
 154  
 155                  $id = self::$builtinNumFormatToIdMapping[$format] ?? $this->formatIndex++;
 156                  $this->styleIdToFormatsMappingTable[$styleId] = $id;
 157              }
 158          } else {
 159              // The formatId maps a style to a format declaration
 160              // When there is no format definition - we default to 0 ( General )
 161              $this->styleIdToFormatsMappingTable[$styleId] = 0;
 162          }
 163      }
 164  
 165      /**
 166       * @param int $styleId
 167       * @return int|null Format ID associated to the given style ID
 168       */
 169      public function getFormatIdForStyleId($styleId)
 170      {
 171          return $this->styleIdToFormatsMappingTable[$styleId] ?? null;
 172      }
 173  
 174      /**
 175       * Register a fill definition
 176       *
 177       * @param Style $style
 178       */
 179      private function registerFill(Style $style)
 180      {
 181          $styleId = $style->getId();
 182  
 183          // Currently - only solid backgrounds are supported
 184          // so $backgroundColor is a scalar value (RGB Color)
 185          $backgroundColor = $style->getBackgroundColor();
 186  
 187          if ($backgroundColor) {
 188              $isBackgroundColorRegistered = isset($this->registeredFills[$backgroundColor]);
 189  
 190              // We need to track the already registered background definitions
 191              if ($isBackgroundColorRegistered) {
 192                  $registeredStyleId = $this->registeredFills[$backgroundColor];
 193                  $registeredFillId = $this->styleIdToFillMappingTable[$registeredStyleId];
 194                  $this->styleIdToFillMappingTable[$styleId] = $registeredFillId;
 195              } else {
 196                  $this->registeredFills[$backgroundColor] = $styleId;
 197                  $this->styleIdToFillMappingTable[$styleId] = $this->fillIndex++;
 198              }
 199          } else {
 200              // The fillId maps a style to a fill declaration
 201              // When there is no background color definition - we default to 0
 202              $this->styleIdToFillMappingTable[$styleId] = 0;
 203          }
 204      }
 205  
 206      /**
 207       * @param int $styleId
 208       * @return int|null Fill ID associated to the given style ID
 209       */
 210      public function getFillIdForStyleId($styleId)
 211      {
 212          return (isset($this->styleIdToFillMappingTable[$styleId])) ?
 213              $this->styleIdToFillMappingTable[$styleId] :
 214              null;
 215      }
 216  
 217      /**
 218       * Register a border definition
 219       *
 220       * @param Style $style
 221       */
 222      private function registerBorder(Style $style)
 223      {
 224          $styleId = $style->getId();
 225  
 226          if ($style->shouldApplyBorder()) {
 227              $border = $style->getBorder();
 228              $serializedBorder = \serialize($border);
 229  
 230              $isBorderAlreadyRegistered = isset($this->registeredBorders[$serializedBorder]);
 231  
 232              if ($isBorderAlreadyRegistered) {
 233                  $registeredStyleId = $this->registeredBorders[$serializedBorder];
 234                  $registeredBorderId = $this->styleIdToBorderMappingTable[$registeredStyleId];
 235                  $this->styleIdToBorderMappingTable[$styleId] = $registeredBorderId;
 236              } else {
 237                  $this->registeredBorders[$serializedBorder] = $styleId;
 238                  $this->styleIdToBorderMappingTable[$styleId] = \count($this->registeredBorders);
 239              }
 240          } else {
 241              // If no border should be applied - the mapping is the default border: 0
 242              $this->styleIdToBorderMappingTable[$styleId] = 0;
 243          }
 244      }
 245  
 246      /**
 247       * @param int $styleId
 248       * @return int|null Fill ID associated to the given style ID
 249       */
 250      public function getBorderIdForStyleId($styleId)
 251      {
 252          return (isset($this->styleIdToBorderMappingTable[$styleId])) ?
 253              $this->styleIdToBorderMappingTable[$styleId] :
 254              null;
 255      }
 256  
 257      /**
 258       * @return array
 259       */
 260      public function getRegisteredFills()
 261      {
 262          return $this->registeredFills;
 263      }
 264  
 265      /**
 266       * @return array
 267       */
 268      public function getRegisteredBorders()
 269      {
 270          return $this->registeredBorders;
 271      }
 272  
 273      /**
 274       * @return array
 275       */
 276      public function getRegisteredFormats()
 277      {
 278          return $this->registeredFormats;
 279      }
 280  }