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.
   1  <?php
   2  
   3  namespace PhpOffice\PhpSpreadsheet\Calculation\Engine;
   4  
   5  use PhpOffice\PhpSpreadsheet\Calculation\Exception;
   6  
   7  class ArrayArgumentHelper
   8  {
   9      /**
  10       * @var int
  11       */
  12      protected $indexStart = 0;
  13  
  14      /**
  15       * @var array
  16       */
  17      protected $arguments;
  18  
  19      /**
  20       * @var int
  21       */
  22      protected $argumentCount;
  23  
  24      /**
  25       * @var array
  26       */
  27      protected $rows;
  28  
  29      /**
  30       * @var array
  31       */
  32      protected $columns;
  33  
  34      public function initialise(array $arguments): void
  35      {
  36          $keys = array_keys($arguments);
  37          $this->indexStart = (int) array_shift($keys);
  38          $this->rows = $this->rows($arguments);
  39          $this->columns = $this->columns($arguments);
  40  
  41          $this->argumentCount = count($arguments);
  42          $this->arguments = $this->flattenSingleCellArrays($arguments, $this->rows, $this->columns);
  43  
  44          $this->rows = $this->rows($arguments);
  45          $this->columns = $this->columns($arguments);
  46  
  47          if ($this->arrayArguments() > 2) {
  48              throw new Exception('Formulae with more than two array arguments are not supported');
  49          }
  50      }
  51  
  52      public function arguments(): array
  53      {
  54          return $this->arguments;
  55      }
  56  
  57      public function hasArrayArgument(): bool
  58      {
  59          return $this->arrayArguments() > 0;
  60      }
  61  
  62      public function getFirstArrayArgumentNumber(): int
  63      {
  64          $rowArrays = $this->filterArray($this->rows);
  65          $columnArrays = $this->filterArray($this->columns);
  66  
  67          for ($index = $this->indexStart; $index < $this->argumentCount; ++$index) {
  68              if (isset($rowArrays[$index]) || isset($columnArrays[$index])) {
  69                  return ++$index;
  70              }
  71          }
  72  
  73          return 0;
  74      }
  75  
  76      public function getSingleRowVector(): ?int
  77      {
  78          $rowVectors = $this->getRowVectors();
  79  
  80          return count($rowVectors) === 1 ? array_pop($rowVectors) : null;
  81      }
  82  
  83      private function getRowVectors(): array
  84      {
  85          $rowVectors = [];
  86          for ($index = $this->indexStart; $index < ($this->indexStart + $this->argumentCount); ++$index) {
  87              if ($this->rows[$index] === 1 && $this->columns[$index] > 1) {
  88                  $rowVectors[] = $index;
  89              }
  90          }
  91  
  92          return $rowVectors;
  93      }
  94  
  95      public function getSingleColumnVector(): ?int
  96      {
  97          $columnVectors = $this->getColumnVectors();
  98  
  99          return count($columnVectors) === 1 ? array_pop($columnVectors) : null;
 100      }
 101  
 102      private function getColumnVectors(): array
 103      {
 104          $columnVectors = [];
 105          for ($index = $this->indexStart; $index < ($this->indexStart + $this->argumentCount); ++$index) {
 106              if ($this->rows[$index] > 1 && $this->columns[$index] === 1) {
 107                  $columnVectors[] = $index;
 108              }
 109          }
 110  
 111          return $columnVectors;
 112      }
 113  
 114      public function getMatrixPair(): array
 115      {
 116          for ($i = $this->indexStart; $i < ($this->indexStart + $this->argumentCount - 1); ++$i) {
 117              for ($j = $i + 1; $j < $this->argumentCount; ++$j) {
 118                  if (isset($this->rows[$i], $this->rows[$j])) {
 119                      return [$i, $j];
 120                  }
 121              }
 122          }
 123  
 124          return [];
 125      }
 126  
 127      public function isVector(int $argument): bool
 128      {
 129          return $this->rows[$argument] === 1 || $this->columns[$argument] === 1;
 130      }
 131  
 132      public function isRowVector(int $argument): bool
 133      {
 134          return $this->rows[$argument] === 1;
 135      }
 136  
 137      public function isColumnVector(int $argument): bool
 138      {
 139          return $this->columns[$argument] === 1;
 140      }
 141  
 142      public function rowCount(int $argument): int
 143      {
 144          return $this->rows[$argument];
 145      }
 146  
 147      public function columnCount(int $argument): int
 148      {
 149          return $this->columns[$argument];
 150      }
 151  
 152      private function rows(array $arguments): array
 153      {
 154          return array_map(
 155              function ($argument) {
 156                  return is_countable($argument) ? count($argument) : 1;
 157              },
 158              $arguments
 159          );
 160      }
 161  
 162      private function columns(array $arguments): array
 163      {
 164          return array_map(
 165              function ($argument) {
 166                  return is_array($argument) && is_array($argument[array_keys($argument)[0]])
 167                      ? count($argument[array_keys($argument)[0]])
 168                      : 1;
 169              },
 170              $arguments
 171          );
 172      }
 173  
 174      public function arrayArguments(): int
 175      {
 176          $count = 0;
 177          foreach (array_keys($this->arguments) as $argument) {
 178              if ($this->rows[$argument] > 1 || $this->columns[$argument] > 1) {
 179                  ++$count;
 180              }
 181          }
 182  
 183          return $count;
 184      }
 185  
 186      private function flattenSingleCellArrays(array $arguments, array $rows, array $columns): array
 187      {
 188          foreach ($arguments as $index => $argument) {
 189              if ($rows[$index] === 1 && $columns[$index] === 1) {
 190                  while (is_array($argument)) {
 191                      $argument = array_pop($argument);
 192                  }
 193                  $arguments[$index] = $argument;
 194              }
 195          }
 196  
 197          return $arguments;
 198      }
 199  
 200      private function filterArray(array $array): array
 201      {
 202          return array_filter(
 203              $array,
 204              function ($value) {
 205                  return $value > 1;
 206              }
 207          );
 208      }
 209  }