Differences Between: [Versions 400 and 402] [Versions 401 and 402]
1 <?php 2 3 namespace PhpOffice\PhpSpreadsheet\Calculation\LookupRef; 4 5 use Exception; 6 use PhpOffice\PhpSpreadsheet\Calculation\Calculation; 7 use PhpOffice\PhpSpreadsheet\Calculation\Functions; 8 use PhpOffice\PhpSpreadsheet\Calculation\Information\ExcelError; 9 use PhpOffice\PhpSpreadsheet\Cell\AddressRange; 10 use PhpOffice\PhpSpreadsheet\Cell\Cell; 11 use PhpOffice\PhpSpreadsheet\Cell\Coordinate; 12 use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet; 13 14 class Indirect 15 { 16 /** 17 * Determine whether cell address is in A1 (true) or R1C1 (false) format. 18 * 19 * @param mixed $a1fmt Expect bool Helpers::CELLADDRESS_USE_A1 or CELLADDRESS_USE_R1C1, 20 * but can be provided as numeric which is cast to bool 21 */ 22 private static function a1Format($a1fmt): bool 23 { 24 $a1fmt = Functions::flattenSingleValue($a1fmt); 25 if ($a1fmt === null) { 26 return Helpers::CELLADDRESS_USE_A1; 27 } 28 if (is_string($a1fmt)) { 29 throw new Exception(ExcelError::VALUE()); 30 } 31 32 return (bool) $a1fmt; 33 } 34 35 /** 36 * Convert cellAddress to string, verify not null string. 37 * 38 * @param array|string $cellAddress 39 */ 40 private static function validateAddress($cellAddress): string 41 { 42 $cellAddress = Functions::flattenSingleValue($cellAddress); 43 if (!is_string($cellAddress) || !$cellAddress) { 44 throw new Exception(ExcelError::REF()); 45 } 46 47 return $cellAddress; 48 } 49 50 /** 51 * INDIRECT. 52 * 53 * Returns the reference specified by a text string. 54 * References are immediately evaluated to display their contents. 55 * 56 * Excel Function: 57 * =INDIRECT(cellAddress, bool) where the bool argument is optional 58 * 59 * @param array|string $cellAddress $cellAddress The cell address of the current cell (containing this formula) 60 * @param mixed $a1fmt Expect bool Helpers::CELLADDRESS_USE_A1 or CELLADDRESS_USE_R1C1, 61 * but can be provided as numeric which is cast to bool 62 * @param Cell $cell The current cell (containing this formula) 63 * 64 * @return array|string An array containing a cell or range of cells, or a string on error 65 */ 66 public static function INDIRECT($cellAddress, $a1fmt, Cell $cell) 67 { 68 [$baseCol, $baseRow] = Coordinate::indexesFromString($cell->getCoordinate()); 69 70 try { 71 $a1 = self::a1Format($a1fmt); 72 $cellAddress = self::validateAddress($cellAddress); 73 } catch (Exception $e) { 74 return $e->getMessage(); 75 } 76 77 [$cellAddress, $worksheet, $sheetName] = Helpers::extractWorksheet($cellAddress, $cell); 78 79 if (preg_match('/^' . Calculation::CALCULATION_REGEXP_COLUMNRANGE_RELATIVE . '$/miu', $cellAddress, $matches)) { 80 $cellAddress = self::handleRowColumnRanges($worksheet, ...explode(':', $cellAddress)); 81 } elseif (preg_match('/^' . Calculation::CALCULATION_REGEXP_ROWRANGE_RELATIVE . '$/miu', $cellAddress, $matches)) { 82 $cellAddress = self::handleRowColumnRanges($worksheet, ...explode(':', $cellAddress)); 83 } 84 85 try { 86 [$cellAddress1, $cellAddress2, $cellAddress] = Helpers::extractCellAddresses($cellAddress, $a1, $cell->getWorkSheet(), $sheetName, $baseRow, $baseCol); 87 } catch (Exception $e) { 88 return ExcelError::REF(); 89 } 90 91 if ( 92 (!preg_match('/^' . Calculation::CALCULATION_REGEXP_CELLREF . '$/miu', $cellAddress1, $matches)) || 93 (($cellAddress2 !== null) && (!preg_match('/^' . Calculation::CALCULATION_REGEXP_CELLREF . '$/miu', $cellAddress2, $matches))) 94 ) { 95 return ExcelError::REF(); 96 } 97 98 return self::extractRequiredCells($worksheet, $cellAddress); 99 } 100 101 /** 102 * Extract range values. 103 * 104 * @return mixed Array of values in range if range contains more than one element. 105 * Otherwise, a single value is returned. 106 */ 107 private static function extractRequiredCells(?Worksheet $worksheet, string $cellAddress) 108 { 109 return Calculation::getInstance($worksheet !== null ? $worksheet->getParent() : null) 110 ->extractCellRange($cellAddress, $worksheet, false); 111 } 112 113 private static function handleRowColumnRanges(?Worksheet $worksheet, string $start, string $end): string 114 { 115 // Being lazy, we're only checking a single row/column to get the max 116 if (ctype_digit($start) && $start <= 1048576) { 117 // Max 16,384 columns for Excel2007 118 $endColRef = ($worksheet !== null) ? $worksheet->getHighestDataColumn((int) $start) : AddressRange::MAX_COLUMN; 119 120 return "A{$start}:{$endColRef}{$end}"; 121 } elseif (ctype_alpha($start) && strlen($start) <= 3) { 122 // Max 1,048,576 rows for Excel2007 123 $endRowRef = ($worksheet !== null) ? $worksheet->getHighestDataRow($start) : AddressRange::MAX_ROW; 124 125 return "{$start}1:{$end}{$endRowRef}"; 126 } 127 128 return "{$start}:{$end}"; 129 } 130 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body