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 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body