Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 3.10.x will end 8 November 2021 (12 months).
  • Bug fixes for security issues in 3.10.x will end 9 May 2022 (18 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 310 and 311] [Versions 310 and 400] [Versions 310 and 401] [Versions 310 and 402] [Versions 310 and 403]

   1  <?php
   2  
   3  namespace PhpOffice\PhpSpreadsheet\Reader\Xlsx;
   4  
   5  use PhpOffice\PhpSpreadsheet\Cell\Coordinate;
   6  use PhpOffice\PhpSpreadsheet\Reader\IReadFilter;
   7  use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
   8  
   9  class ColumnAndRowAttributes extends BaseParserClass
  10  {
  11      private $worksheet;
  12  
  13      private $worksheetXml;
  14  
  15      public function __construct(Worksheet $workSheet, \SimpleXMLElement $worksheetXml = null)
  16      {
  17          $this->worksheet = $workSheet;
  18          $this->worksheetXml = $worksheetXml;
  19      }
  20  
  21      /**
  22       * Set Worksheet column attributes by attributes array passed.
  23       *
  24       * @param string $columnAddress A, B, ... DX, ...
  25       * @param array $columnAttributes array of attributes (indexes are attribute name, values are value)
  26       *                               'xfIndex', 'visible', 'collapsed', 'outlineLevel', 'width', ... ?
  27       */
  28      private function setColumnAttributes($columnAddress, array $columnAttributes)
  29      {
  30          if (isset($columnAttributes['xfIndex'])) {
  31              $this->worksheet->getColumnDimension($columnAddress)->setXfIndex($columnAttributes['xfIndex']);
  32          }
  33          if (isset($columnAttributes['visible'])) {
  34              $this->worksheet->getColumnDimension($columnAddress)->setVisible($columnAttributes['visible']);
  35          }
  36          if (isset($columnAttributes['collapsed'])) {
  37              $this->worksheet->getColumnDimension($columnAddress)->setCollapsed($columnAttributes['collapsed']);
  38          }
  39          if (isset($columnAttributes['outlineLevel'])) {
  40              $this->worksheet->getColumnDimension($columnAddress)->setOutlineLevel($columnAttributes['outlineLevel']);
  41          }
  42          if (isset($columnAttributes['width'])) {
  43              $this->worksheet->getColumnDimension($columnAddress)->setWidth($columnAttributes['width']);
  44          }
  45      }
  46  
  47      /**
  48       * Set Worksheet row attributes by attributes array passed.
  49       *
  50       * @param int $rowNumber 1, 2, 3, ... 99, ...
  51       * @param array $rowAttributes array of attributes (indexes are attribute name, values are value)
  52       *                               'xfIndex', 'visible', 'collapsed', 'outlineLevel', 'rowHeight', ... ?
  53       */
  54      private function setRowAttributes($rowNumber, array $rowAttributes)
  55      {
  56          if (isset($rowAttributes['xfIndex'])) {
  57              $this->worksheet->getRowDimension($rowNumber)->setXfIndex($rowAttributes['xfIndex']);
  58          }
  59          if (isset($rowAttributes['visible'])) {
  60              $this->worksheet->getRowDimension($rowNumber)->setVisible($rowAttributes['visible']);
  61          }
  62          if (isset($rowAttributes['collapsed'])) {
  63              $this->worksheet->getRowDimension($rowNumber)->setCollapsed($rowAttributes['collapsed']);
  64          }
  65          if (isset($rowAttributes['outlineLevel'])) {
  66              $this->worksheet->getRowDimension($rowNumber)->setOutlineLevel($rowAttributes['outlineLevel']);
  67          }
  68          if (isset($rowAttributes['rowHeight'])) {
  69              $this->worksheet->getRowDimension($rowNumber)->setRowHeight($rowAttributes['rowHeight']);
  70          }
  71      }
  72  
  73      /**
  74       * @param IReadFilter $readFilter
  75       * @param bool $readDataOnly
  76       */
  77      public function load(IReadFilter $readFilter = null, $readDataOnly = false)
  78      {
  79          if ($this->worksheetXml === null) {
  80              return;
  81          }
  82  
  83          $columnsAttributes = [];
  84          $rowsAttributes = [];
  85          if (isset($this->worksheetXml->cols)) {
  86              $columnsAttributes = $this->readColumnAttributes($this->worksheetXml->cols, $readDataOnly);
  87          }
  88  
  89          if ($this->worksheetXml->sheetData && $this->worksheetXml->sheetData->row) {
  90              $rowsAttributes = $this->readRowAttributes($this->worksheetXml->sheetData->row, $readDataOnly);
  91          }
  92  
  93          // set columns/rows attributes
  94          $columnsAttributesAreSet = [];
  95          foreach ($columnsAttributes as $columnCoordinate => $columnAttributes) {
  96              if ($readFilter === null ||
  97                  !$this->isFilteredColumn($readFilter, $columnCoordinate, $rowsAttributes)) {
  98                  if (!isset($columnsAttributesAreSet[$columnCoordinate])) {
  99                      $this->setColumnAttributes($columnCoordinate, $columnAttributes);
 100                      $columnsAttributesAreSet[$columnCoordinate] = true;
 101                  }
 102              }
 103          }
 104  
 105          $rowsAttributesAreSet = [];
 106          foreach ($rowsAttributes as $rowCoordinate => $rowAttributes) {
 107              if ($readFilter === null ||
 108                  !$this->isFilteredRow($readFilter, $rowCoordinate, $columnsAttributes)) {
 109                  if (!isset($rowsAttributesAreSet[$rowCoordinate])) {
 110                      $this->setRowAttributes($rowCoordinate, $rowAttributes);
 111                      $rowsAttributesAreSet[$rowCoordinate] = true;
 112                  }
 113              }
 114          }
 115      }
 116  
 117      private function isFilteredColumn(IReadFilter $readFilter, $columnCoordinate, array $rowsAttributes)
 118      {
 119          foreach ($rowsAttributes as $rowCoordinate => $rowAttributes) {
 120              if (!$readFilter->readCell($columnCoordinate, $rowCoordinate, $this->worksheet->getTitle())) {
 121                  return true;
 122              }
 123          }
 124  
 125          return false;
 126      }
 127  
 128      private function readColumnAttributes(\SimpleXMLElement $worksheetCols, $readDataOnly)
 129      {
 130          $columnAttributes = [];
 131  
 132          foreach ($worksheetCols->col as $column) {
 133              $startColumn = Coordinate::stringFromColumnIndex((int) $column['min']);
 134              $endColumn = Coordinate::stringFromColumnIndex((int) $column['max']);
 135              ++$endColumn;
 136              for ($columnAddress = $startColumn; $columnAddress !== $endColumn; ++$columnAddress) {
 137                  $columnAttributes[$columnAddress] = $this->readColumnRangeAttributes($column, $readDataOnly);
 138  
 139                  if ((int) ($column['max']) == 16384) {
 140                      break;
 141                  }
 142              }
 143          }
 144  
 145          return $columnAttributes;
 146      }
 147  
 148      private function readColumnRangeAttributes(\SimpleXMLElement $column, $readDataOnly)
 149      {
 150          $columnAttributes = [];
 151  
 152          if ($column['style'] && !$readDataOnly) {
 153              $columnAttributes['xfIndex'] = (int) $column['style'];
 154          }
 155          if (self::boolean($column['hidden'])) {
 156              $columnAttributes['visible'] = false;
 157          }
 158          if (self::boolean($column['collapsed'])) {
 159              $columnAttributes['collapsed'] = true;
 160          }
 161          if (((int) $column['outlineLevel']) > 0) {
 162              $columnAttributes['outlineLevel'] = (int) $column['outlineLevel'];
 163          }
 164          $columnAttributes['width'] = (float) $column['width'];
 165  
 166          return $columnAttributes;
 167      }
 168  
 169      private function isFilteredRow(IReadFilter $readFilter, $rowCoordinate, array $columnsAttributes)
 170      {
 171          foreach ($columnsAttributes as $columnCoordinate => $columnAttributes) {
 172              if (!$readFilter->readCell($columnCoordinate, $rowCoordinate, $this->worksheet->getTitle())) {
 173                  return true;
 174              }
 175          }
 176  
 177          return false;
 178      }
 179  
 180      private function readRowAttributes(\SimpleXMLElement $worksheetRow, $readDataOnly)
 181      {
 182          $rowAttributes = [];
 183  
 184          foreach ($worksheetRow as $row) {
 185              if ($row['ht'] && !$readDataOnly) {
 186                  $rowAttributes[(int) $row['r']]['rowHeight'] = (float) $row['ht'];
 187              }
 188              if (self::boolean($row['hidden'])) {
 189                  $rowAttributes[(int) $row['r']]['visible'] = false;
 190              }
 191              if (self::boolean($row['collapsed'])) {
 192                  $rowAttributes[(int) $row['r']]['collapsed'] = true;
 193              }
 194              if ((int) $row['outlineLevel'] > 0) {
 195                  $rowAttributes[(int) $row['r']]['outlineLevel'] = (int) $row['outlineLevel'];
 196              }
 197              if ($row['s'] && !$readDataOnly) {
 198                  $rowAttributes[(int) $row['r']]['xfIndex'] = (int) $row['s'];
 199              }
 200          }
 201  
 202          return $rowAttributes;
 203      }
 204  }