← All changes
|
libraries/vendor/PhpSpreadsheet/Worksheet/Worksheet.php
+248
-14
3.3.1
→
3.4
View file →
| @@ -31,8 +31,12 @@ | ||
| 31 | 31 | use TablePress\PhpOffice\PhpSpreadsheet\Style\Conditional; |
| 32 | 32 | use TablePress\PhpOffice\PhpSpreadsheet\Style\NumberFormat; |
| 33 | 33 | use TablePress\PhpOffice\PhpSpreadsheet\Style\Protection as StyleProtection; |
| 34 | 34 | use TablePress\PhpOffice\PhpSpreadsheet\Style\Style; |
| 35 | +use TablePress\PhpOffice\PhpSpreadsheet\Worksheet\PivotTable\PivotTable; | |
| 36 | +use TablePress\PhpOffice\PhpSpreadsheet\Worksheet\Sparkline\Sparkline; | |
| 37 | +use TablePress\PhpOffice\PhpSpreadsheet\Worksheet\Sparkline\SparklineGroup; | |
| 38 | +use TablePress\PhpOffice\PhpSpreadsheet\Worksheet\Sparkline\SparklineType; | |
| 35 | 39 | |
| 36 | 40 | class Worksheet |
| 37 | 41 | { |
| 38 | 42 | // Break types |
| @@ -129,8 +133,22 @@ | ||
| 129 | 133 | */ |
| 130 | 134 | private ArrayObject $tableCollection; |
| 131 | 135 | |
| 132 | 136 | /** |
| 137 | + * Collection of SparklineGroup objects. | |
| 138 | + * | |
| 139 | + * @var ArrayObject<int, SparklineGroup> | |
| 140 | + */ | |
| 141 | + private ArrayObject $sparklineGroupCollection; | |
| 142 | + | |
| 143 | + /** | |
| 144 | + * Collection of PivotTable objects. | |
| 145 | + * | |
| 146 | + * @var ArrayObject<int, PivotTable> | |
| 147 | + */ | |
| 148 | + private ArrayObject $pivotTableCollection; | |
| 149 | + | |
| 150 | + /** | |
| 133 | 151 | * Worksheet title. |
| 134 | 152 | */ |
| 135 | 153 | private string $title = ''; |
| 136 | 154 | |
| @@ -324,9 +342,11 @@ | ||
| 324 | 342 | public function __construct(?Spreadsheet $parent = null, string $title = 'Worksheet') |
| 325 | 343 | { |
| 326 | 344 | // Set parent and title |
| 327 | 345 | $this->parent = $parent; |
| 328 | - $this->setTitle($title, false); | |
| 346 | + // Chart collection must be set before title | |
| 347 | + $this->chartCollection = new ArrayObject(); | |
| 348 | + $this->setTitle($title, false, true, false); | |
| 329 | 349 | // setTitle can change $pTitle |
| 330 | 350 | $this->setCodeName($this->getTitle()); |
| 331 | 351 | $this->setSheetState(self::SHEETSTATE_VISIBLE); |
| 332 | 352 | |
| @@ -342,10 +362,8 @@ | ||
| 342 | 362 | // Drawing collection |
| 343 | 363 | $this->drawingCollection = new ArrayObject(); |
| 344 | 364 | // In Cell Drawing collection |
| 345 | 365 | $this->inCellDrawingCollection = new ArrayObject(); |
| 346 | - // Chart collection | |
| 347 | - $this->chartCollection = new ArrayObject(); | |
| 348 | 366 | // Protection |
| 349 | 367 | $this->protection = new Protection(); |
| 350 | 368 | // Default row dimension |
| 351 | 369 | $this->defaultRowDimension = new RowDimension(null); |
| @@ -354,17 +372,24 @@ | ||
| 354 | 372 | // AutoFilter |
| 355 | 373 | $this->autoFilter = new AutoFilter('', $this); |
| 356 | 374 | // Table collection |
| 357 | 375 | $this->tableCollection = new ArrayObject(); |
| 376 | + // Sparkline group collection | |
| 377 | + $this->sparklineGroupCollection = new ArrayObject(); | |
| 378 | + | |
| 379 | + // Pivot table collection | |
| 380 | + $this->pivotTableCollection = new ArrayObject(); | |
| 358 | 381 | } |
| 359 | 382 | |
| 360 | 383 | /** |
| 361 | 384 | * Disconnect all cells from this Worksheet object, |
| 362 | 385 | * typically so that the worksheet object can be unset. |
| 386 | + * The worksheet will be in an unusable state after | |
| 387 | + * this method has completed. | |
| 363 | 388 | */ |
| 364 | 389 | public function disconnectCells(): void |
| 365 | 390 | { |
| 366 | - if (isset($this->cellCollection)) { //* @phpstan-ignore-line | |
| 391 | + if (isset($this->cellCollection)) { //* @phpstan-ignore isset.initializedProperty (may be null at destruct time) | |
| 367 | 392 | $this->cellCollection->unsetWorksheetCells(); |
| 368 | 393 | unset($this->cellCollection); |
| 369 | 394 | } |
| 370 | 395 | // detach ourself from the workbook, so that it can then delete this worksheet successfully |
| @@ -378,9 +403,9 @@ | ||
| 378 | 403 | { |
| 379 | 404 | ($nullsafeVariable1 = Calculation::getInstanceOrNull($this->parent)) ? $nullsafeVariable1->clearCalculationCacheForWorksheet($this->title) : null; |
| 380 | 405 | |
| 381 | 406 | $this->disconnectCells(); |
| 382 | - unset($this->rowDimensions, $this->columnDimensions, $this->tableCollection, $this->drawingCollection, $this->inCellDrawingCollection, $this->chartCollection, $this->autoFilter); | |
| 407 | + unset($this->rowDimensions, $this->columnDimensions, $this->tableCollection, $this->sparklineGroupCollection, $this->drawingCollection, $this->inCellDrawingCollection, $this->chartCollection, $this->autoFilter, $this->pivotTableCollection); | |
| 383 | 408 | } |
| 384 | 409 | |
| 385 | 410 | /** |
| 386 | 411 | * Return the cell collection. |
| @@ -460,9 +485,9 @@ | ||
| 460 | 485 | * @return string[] |
| 461 | 486 | */ |
| 462 | 487 | public function getCoordinates(bool $sorted = true): array |
| 463 | 488 | { |
| 464 | - if (!isset($this->cellCollection)) { //* @phpstan-ignore-line | |
| 489 | + if (!isset($this->cellCollection)) { //* @phpstan-ignore isset.initializedProperty (may be null at destruct time) | |
| 465 | 490 | return []; |
| 466 | 491 | } |
| 467 | 492 | |
| 468 | 493 | if ($sorted) { |
| @@ -567,16 +592,16 @@ | ||
| 567 | 592 | |
| 568 | 593 | /** |
| 569 | 594 | * Get a chart by its index position. |
| 570 | 595 | * |
| 571 | - * @param ?string $index Chart index position | |
| 596 | + * @param null|int|string $index Chart index position | |
| 572 | 597 | * |
| 573 | 598 | * @return Chart|false |
| 574 | 599 | */ |
| 575 | - public function getChartByIndex(?string $index) | |
| 600 | + public function getChartByIndex($index) | |
| 576 | 601 | { |
| 577 | 602 | $chartCount = count($this->chartCollection); |
| 578 | - if ($chartCount == 0) { | |
| 603 | + if ($chartCount === 0 || (is_string($index) && $index !== (string) (int) $index)) { | |
| 579 | 604 | return false; |
| 580 | 605 | } |
| 581 | 606 | if ($index === null) { |
| 582 | 607 | $index = --$chartCount; |
| @@ -794,9 +819,11 @@ | ||
| 794 | 819 | } |
| 795 | 820 | $this->activePane = $holdActivePane; |
| 796 | 821 | } |
| 797 | 822 | if ($activeSheet !== null && $activeSheet >= 0) { |
| 798 | - ($nullsafeVariable3 = $this->getParent()) ? $nullsafeVariable3->setActiveSheetIndex($activeSheet) : null; | |
| 823 | + // Okay, I get it now - if $activeSheet is not null, | |
| 824 | + // then $this->getParent() must also be non-null. | |
| 825 | + $this->getParent()->setActiveSheetIndex($activeSheet); | |
| 799 | 826 | } |
| 800 | 827 | $this->setSelectedCells($selectedCells); |
| 801 | 828 | |
| 802 | 829 | return $this; |
| @@ -872,9 +899,9 @@ | ||
| 872 | 899 | * at parse time (by Readers), where titles can be assumed to be valid. |
| 873 | 900 | * |
| 874 | 901 | * @return $this |
| 875 | 902 | */ |
| 876 | - public function setTitle(string $title, bool $updateFormulaCellReferences = true, bool $validate = true) | |
| 903 | + public function setTitle(string $title, bool $updateFormulaCellReferences = true, bool $validate = true, bool $changeChartSheetNames = true) | |
| 877 | 904 | { |
| 878 | 905 | // Is this a 'rename' or not? |
| 879 | 906 | if ($this->getTitle() == $title) { |
| 880 | 907 | return $this; |
| @@ -925,12 +952,63 @@ | ||
| 925 | 952 | if ($updateFormulaCellReferences) { |
| 926 | 953 | ReferenceHelper::getInstance()->updateNamedFormulae($this->parent, $oldTitle, $newTitle); |
| 927 | 954 | } |
| 928 | 955 | } |
| 956 | + if ($changeChartSheetNames) { | |
| 957 | + $this->changeChartSheetNames($oldTitle, $title); | |
| 958 | + } | |
| 929 | 959 | |
| 930 | 960 | return $this; |
| 931 | 961 | } |
| 932 | 962 | |
| 963 | + private function changeChartSheetNames(string $oldTitle, string $title): void | |
| 964 | + { | |
| 965 | + $worksheets = [$this]; | |
| 966 | + if ($this->parent !== null) { | |
| 967 | + $sheets = $this->parent->getAllSheets(); | |
| 968 | + if (in_array($this, $sheets, true)) { | |
| 969 | + $worksheets = $sheets; | |
| 970 | + } | |
| 971 | + } | |
| 972 | + $titleq = "'$title'!"; | |
| 973 | + $oldTitleq1 = preg_quote("'$oldTitle'!"); | |
| 974 | + $oldTitleq2 = preg_quote("$oldTitle!"); | |
| 975 | + $preg1 = "/$oldTitleq1|\\b$oldTitleq2/"; | |
| 976 | + foreach ($worksheets as $sheet) { | |
| 977 | + foreach ($sheet->getChartCollection() as $chart) { | |
| 978 | + foreach (((($nullsafeVariable3 = $chart->getPlotArea()) ? $nullsafeVariable3->getPlotGroup() : null) ?? []) as $plotGroup) { | |
| 979 | + foreach ($plotGroup->getPlotCategories() as $plotCategory) { | |
| 980 | + $dataSource = (string) $plotCategory->getDataSource(); | |
| 981 | + $dataSource2 = Preg::replace($preg1, $titleq, $dataSource); | |
| 982 | + if ($dataSource2 !== $dataSource) { | |
| 983 | + $plotCategory->setDataSource( | |
| 984 | + $dataSource2 | |
| 985 | + ); | |
| 986 | + } | |
| 987 | + } | |
| 988 | + foreach ($plotGroup->getPlotLabels() as $plotLabel) { | |
| 989 | + $dataSource = (string) $plotLabel->getDataSource(); | |
| 990 | + $dataSource2 = Preg::replace($preg1, $titleq, $dataSource); | |
| 991 | + if ($dataSource2 !== $dataSource) { | |
| 992 | + $plotLabel->setDataSource( | |
| 993 | + $dataSource2 | |
| 994 | + ); | |
| 995 | + } | |
| 996 | + } | |
| 997 | + foreach ($plotGroup->getPlotValues() as $plotValue) { | |
| 998 | + $dataSource = (string) $plotValue->getDataSource(); | |
| 999 | + $dataSource2 = Preg::replace($preg1, $titleq, $dataSource); | |
| 1000 | + if ($dataSource2 !== $dataSource) { | |
| 1001 | + $plotValue->setDataSource( | |
| 1002 | + $dataSource2 | |
| 1003 | + ); | |
| 1004 | + } | |
| 1005 | + } | |
| 1006 | + } | |
| 1007 | + } | |
| 1008 | + } | |
| 1009 | + } | |
| 1010 | + | |
| 933 | 1011 | /** |
| 934 | 1012 | * Get sheet state. |
| 935 | 1013 | * |
| 936 | 1014 | * @return string Sheet state (visible, hidden, veryHidden) |
| @@ -1231,10 +1309,9 @@ | ||
| 1231 | 1309 | if ($sheet === null) { |
| 1232 | 1310 | throw new Exception('Sheet not found for named range: ' . $namedRange->getName()); |
| 1233 | 1311 | } |
| 1234 | 1312 | |
| 1235 | - /** @phpstan-ignore-next-line */ | |
| 1236 | - $cellCoordinate = ltrim((string) substr($namedRange->getValue(), strrpos($namedRange->getValue(), '!')), '!'); | |
| 1313 | + $cellCoordinate = ltrim((string) substr($namedRange->getValue(), (int) strrpos($namedRange->getValue(), '!')), '!'); | |
| 1237 | 1314 | $finalCoordinate = str_replace('$', '', $cellCoordinate); |
| 1238 | 1315 | } |
| 1239 | 1316 | } |
| 1240 | 1317 | |
| @@ -1676,9 +1753,9 @@ | ||
| 1676 | 1753 | */ |
| 1677 | 1754 | public function duplicateConditionalStyle(array $styles, string $range = '') |
| 1678 | 1755 | { |
| 1679 | 1756 | foreach ($styles as $cellStyle) { |
| 1680 | - if (!($cellStyle instanceof Conditional)) { // @phpstan-ignore-line | |
| 1757 | + if (!($cellStyle instanceof Conditional)) { | |
| 1681 | 1758 | throw new Exception('Style is not a conditional style'); |
| 1682 | 1759 | } |
| 1683 | 1760 | } |
| 1684 | 1761 | |
| @@ -2165,8 +2242,136 @@ | ||
| 2165 | 2242 | return $this; |
| 2166 | 2243 | } |
| 2167 | 2244 | |
| 2168 | 2245 | /** |
| 2246 | + * Get collection of SparklineGroups. | |
| 2247 | + * | |
| 2248 | + * @return ArrayObject<int, SparklineGroup> | |
| 2249 | + */ | |
| 2250 | + public function getSparklineGroupCollection(): ArrayObject | |
| 2251 | + { | |
| 2252 | + return $this->sparklineGroupCollection; | |
| 2253 | + } | |
| 2254 | + | |
| 2255 | + /** | |
| 2256 | + * Add a SparklineGroup. | |
| 2257 | + * | |
| 2258 | + * @return $this | |
| 2259 | + */ | |
| 2260 | + public function addSparklineGroup(SparklineGroup $sparklineGroup): self | |
| 2261 | + { | |
| 2262 | + $this->sparklineGroupCollection[] = $sparklineGroup; | |
| 2263 | + | |
| 2264 | + return $this; | |
| 2265 | + } | |
| 2266 | + | |
| 2267 | + /** | |
| 2268 | + * Add a single Sparkline, wrapping it in its own SparklineGroup. | |
| 2269 | + * | |
| 2270 | + * This is a convenience method for the common case of adding one sparkline | |
| 2271 | + * with default formatting; the created group is returned so its formatting | |
| 2272 | + * can be adjusted. | |
| 2273 | + * | |
| 2274 | + * @param mixed $type the type of sparkline (defaults to line) | |
| 2275 | + * @param \TablePress\PhpOffice\PhpSpreadsheet\Worksheet\Sparkline\SparklineType::* $type | |
| 2276 | + */ | |
| 2277 | + public function addSparkline(Sparkline $sparkline, $type = SparklineType::Line): SparklineGroup | |
| 2278 | + { | |
| 2279 | + $group = new SparklineGroup(); | |
| 2280 | + $group->setType($type); | |
| 2281 | + $group->addSparkline($sparkline); | |
| 2282 | + $this->addSparklineGroup($group); | |
| 2283 | + | |
| 2284 | + return $group; | |
| 2285 | + } | |
| 2286 | + | |
| 2287 | + /** | |
| 2288 | + * Remove all SparklineGroups. | |
| 2289 | + * | |
| 2290 | + * @return $this | |
| 2291 | + */ | |
| 2292 | + public function removeSparklineGroupCollection(): self | |
| 2293 | + { | |
| 2294 | + $this->sparklineGroupCollection = new ArrayObject(); | |
| 2295 | + | |
| 2296 | + return $this; | |
| 2297 | + } | |
| 2298 | + | |
| 2299 | + /** | |
| 2300 | + * Get collection of PivotTables. | |
| 2301 | + * | |
| 2302 | + * @return ArrayObject<int, PivotTable> | |
| 2303 | + */ | |
| 2304 | + public function getPivotTableCollection(): ArrayObject | |
| 2305 | + { | |
| 2306 | + return $this->pivotTableCollection; | |
| 2307 | + } | |
| 2308 | + | |
| 2309 | + /** | |
| 2310 | + * Get collection of PivotTables (alias of getPivotTableCollection()). | |
| 2311 | + * | |
| 2312 | + * @return ArrayObject<int, PivotTable> | |
| 2313 | + */ | |
| 2314 | + public function getPivotTables(): ArrayObject | |
| 2315 | + { | |
| 2316 | + return $this->pivotTableCollection; | |
| 2317 | + } | |
| 2318 | + | |
| 2319 | + /** | |
| 2320 | + * Add a PivotTable to this worksheet. | |
| 2321 | + * | |
| 2322 | + * @return $this | |
| 2323 | + */ | |
| 2324 | + public function addPivotTable(PivotTable $pivotTable): self | |
| 2325 | + { | |
| 2326 | + $pivotTable->setWorksheet($this); | |
| 2327 | + $this->pivotTableCollection[] = $pivotTable; | |
| 2328 | + | |
| 2329 | + return $this; | |
| 2330 | + } | |
| 2331 | + | |
| 2332 | + /** | |
| 2333 | + * @return string[] array of PivotTable names | |
| 2334 | + */ | |
| 2335 | + public function getPivotTableNames(): array | |
| 2336 | + { | |
| 2337 | + $pivotTableNames = []; | |
| 2338 | + | |
| 2339 | + foreach ($this->pivotTableCollection as $pivotTable) { | |
| 2340 | + $pivotTableNames[] = $pivotTable->getName(); | |
| 2341 | + } | |
| 2342 | + | |
| 2343 | + return $pivotTableNames; | |
| 2344 | + } | |
| 2345 | + | |
| 2346 | + /** | |
| 2347 | + * @param string $name the pivot table name to search | |
| 2348 | + * | |
| 2349 | + * @return null|PivotTable The pivot table from the collection, or null if not found | |
| 2350 | + */ | |
| 2351 | + public function getPivotTableByName(string $name): ?PivotTable | |
| 2352 | + { | |
| 2353 | + $name = StringHelper::strToUpper($name); | |
| 2354 | + foreach ($this->pivotTableCollection as $pivotTable) { | |
| 2355 | + if (StringHelper::strToUpper($pivotTable->getName()) === $name) { | |
| 2356 | + return $pivotTable; | |
| 2357 | + } | |
| 2358 | + } | |
| 2359 | + | |
| 2360 | + return null; | |
| 2361 | + } | |
| 2362 | + | |
| 2363 | + /** | |
| 2364 | + * Remove collection of PivotTables. | |
| 2365 | + */ | |
| 2366 | + public function removePivotTableCollection(): self | |
| 2367 | + { | |
| 2368 | + $this->pivotTableCollection = new ArrayObject(); | |
| 2369 | + | |
| 2370 | + return $this; | |
| 2371 | + } | |
| 2372 | + | |
| 2373 | + /** | |
| 2169 | 2374 | * Get Freeze Pane. |
| 2170 | 2375 | */ |
| 2171 | 2376 | public function getFreezePane(): ?string |
| 2172 | 2377 | { |
| @@ -2436,8 +2641,20 @@ | ||
| 2436 | 2641 | { |
| 2437 | 2642 | if ($row < 1) { |
| 2438 | 2643 | throw new Exception('Rows to be deleted should at least start from row 1.'); |
| 2439 | 2644 | } |
| 2645 | + if ($numberOfRows === 0) { | |
| 2646 | + return $this; | |
| 2647 | + } | |
| 2648 | + if ($numberOfRows < 0) { | |
| 2649 | + $newRow = max(1, $row + $numberOfRows + 1); | |
| 2650 | + $numberOfRows = $row - $newRow + 1; | |
| 2651 | + $row = $newRow; | |
| 2652 | + } | |
| 2653 | + $newHighestRow = $this->cachedHighestRow; | |
| 2654 | + if ($newHighestRow >= $row) { | |
| 2655 | + $newHighestRow = max($row - 1, $this->cachedHighestRow - $numberOfRows); | |
| 2656 | + } | |
| 2440 | 2657 | $startRow = $row; |
| 2441 | 2658 | $endRow = $startRow + $numberOfRows - 1; |
| 2442 | 2659 | $removeKeys = []; |
| 2443 | 2660 | $addKeys = []; |
| @@ -2492,8 +2709,9 @@ | ||
| 2492 | 2709 | --$highestRow; |
| 2493 | 2710 | } |
| 2494 | 2711 | |
| 2495 | 2712 | $this->rowDimensions = $holdRowDimensions; |
| 2713 | + $this->cachedHighestRow = $newHighestRow; | |
| 2496 | 2714 | |
| 2497 | 2715 | return $this; |
| 2498 | 2716 | } |
| 2499 | 2717 | |
| @@ -2530,8 +2748,21 @@ | ||
| 2530 | 2748 | if (is_numeric($column)) { |
| 2531 | 2749 | throw new Exception('Column references should not be numeric.'); |
| 2532 | 2750 | } |
| 2533 | 2751 | $startColumnInt = Coordinate::columnIndexFromString($column); |
| 2752 | + if ($numberOfColumns === 0) { | |
| 2753 | + return $this; | |
| 2754 | + } | |
| 2755 | + if ($numberOfColumns < 0) { | |
| 2756 | + $newStartColumnInt = max(1, $startColumnInt + $numberOfColumns + 1); | |
| 2757 | + $numberOfColumns = $startColumnInt - $newStartColumnInt + 1; | |
| 2758 | + $startColumnInt = $newStartColumnInt; | |
| 2759 | + $column = Coordinate::stringFromColumnIndex($startColumnInt); | |
| 2760 | + } | |
| 2761 | + $newHighestColumn = $this->cachedHighestColumn; | |
| 2762 | + if ($newHighestColumn >= $startColumnInt) { | |
| 2763 | + $newHighestColumn = max($startColumnInt - 1, $this->cachedHighestColumn - $numberOfColumns); | |
| 2764 | + } | |
| 2534 | 2765 | $endColumnInt = $startColumnInt + $numberOfColumns - 1; |
| 2535 | 2766 | $removeKeys = []; |
| 2536 | 2767 | $addKeys = []; |
| 2537 | 2768 | foreach ($this->mergeCells as $key => $value) { |
| @@ -2580,8 +2811,10 @@ | ||
| 2580 | 2811 | |
| 2581 | 2812 | $this->columnDimensions = $holdColumnDimensions; |
| 2582 | 2813 | |
| 2583 | 2814 | if ($pColumnIndex > $highestColumnIndex) { |
| 2815 | + $this->cachedHighestColumn = $newHighestColumn; | |
| 2816 | + | |
| 2584 | 2817 | return $this; |
| 2585 | 2818 | } |
| 2586 | 2819 | |
| 2587 | 2820 | $maxPossibleColumnsToBeRemoved = $highestColumnIndex - $pColumnIndex + 1; |
| @@ -2589,8 +2822,9 @@ | ||
| 2589 | 2822 | for ($c = 0, $n = min($maxPossibleColumnsToBeRemoved, $numberOfColumns); $c < $n; ++$c) { |
| 2590 | 2823 | $this->cellCollection->removeColumn($highestColumn); |
| 2591 | 2824 | $highestColumn = Coordinate::stringFromColumnIndex(Coordinate::columnIndexFromString($highestColumn) - 1); |
| 2592 | 2825 | } |
| 2826 | + $this->cachedHighestColumn = $newHighestColumn; | |
| 2593 | 2827 | |
| 2594 | 2828 | $this->garbageCollect(); |
| 2595 | 2829 | |
| 2596 | 2830 | return $this; |