IndirectTest.php 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. <?php
  2. namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\LookupRef;
  3. use PhpOffice\PhpSpreadsheet\NamedRange;
  4. use PhpOffice\PhpSpreadsheet\Reader\Xlsx as ReaderXlsx;
  5. class IndirectTest extends AllSetupTeardown
  6. {
  7. /**
  8. * @dataProvider providerINDIRECT
  9. *
  10. * @param mixed $expectedResult
  11. * @param mixed $cellReference
  12. * @param mixed $a1
  13. */
  14. public function testINDIRECT($expectedResult, $cellReference = 'omitted', $a1 = 'omitted'): void
  15. {
  16. $this->mightHaveException($expectedResult);
  17. $sheet = $this->getSheet();
  18. $sheet->getCell('A1')->setValue(100);
  19. $sheet->getCell('A2')->setValue(200);
  20. $sheet->getCell('A3')->setValue(300);
  21. $sheet->getCell('A4')->setValue(400);
  22. $sheet->getCell('A5')->setValue(500);
  23. $sheet->setTitle('ThisSheet');
  24. $sheet1 = $this->getSpreadsheet()->createSheet();
  25. $sheet1->getCell('A1')->setValue(10);
  26. $sheet1->getCell('A2')->setValue(20);
  27. $sheet1->getCell('A3')->setValue(30);
  28. $sheet1->getCell('A4')->setValue(40);
  29. $sheet1->getCell('A5')->setValue(50);
  30. $sheet1->getCell('B1')->setValue(1);
  31. $sheet1->getCell('B2')->setValue(2);
  32. $sheet1->getCell('B3')->setValue(3);
  33. $sheet1->getCell('B4')->setValue(4);
  34. $sheet1->getCell('B5')->setValue(5);
  35. $sheet1->setTitle('OtherSheet');
  36. $this->getSpreadsheet()->addNamedRange(new NamedRange('newnr', $sheet1, '$A$2:$A$4'));
  37. $this->getSpreadsheet()->addNamedRange(new NamedRange('localname', $sheet1, '$B$2:$B$4', true));
  38. $this->setCell('B1', $cellReference);
  39. $this->setCell('B2', $a1);
  40. if ($cellReference === 'omitted') {
  41. $sheet->getCell('B3')->setValue('=SUM(INDIRECT())');
  42. } elseif ($a1 === 'omitted') {
  43. $sheet->getCell('B3')->setValue('=SUM(INDIRECT(B1))');
  44. } else {
  45. $sheet->getCell('B3')->setValue('=SUM(INDIRECT(B1, B2))');
  46. }
  47. $result = $sheet->getCell('B3')->getCalculatedValue();
  48. self::assertSame($expectedResult, $result);
  49. }
  50. public function providerINDIRECT(): array
  51. {
  52. return require 'tests/data/Calculation/LookupRef/INDIRECT.php';
  53. }
  54. public function testINDIRECTEurUsd(): void
  55. {
  56. $sheet = $this->getSheet();
  57. $sheet->getCell('A1')->setValue('EUR');
  58. $sheet->getCell('A2')->setValue('USD');
  59. $sheet->getCell('B1')->setValue(360);
  60. $sheet->getCell('B2')->setValue(300);
  61. $this->getSpreadsheet()->addNamedRange(new NamedRange('EUR', $sheet, '$B$1'));
  62. $this->getSpreadsheet()->addNamedRange(new NamedRange('USD', $sheet, '$B$2'));
  63. $this->setCell('E1', '=INDIRECT("USD")');
  64. $result = $sheet->getCell('E1')->getCalculatedValue();
  65. self::assertSame(300, $result);
  66. }
  67. public function testINDIRECTLeadingEquals(): void
  68. {
  69. $sheet = $this->getSheet();
  70. $sheet->getCell('A1')->setValue('EUR');
  71. $sheet->getCell('A2')->setValue('USD');
  72. $sheet->getCell('B1')->setValue(360);
  73. $sheet->getCell('B2')->setValue(300);
  74. $this->getSpreadsheet()->addNamedRange(new NamedRange('EUR', $sheet, '=$B$1'));
  75. $this->getSpreadsheet()->addNamedRange(new NamedRange('USD', $sheet, '=$B$2'));
  76. $this->setCell('E1', '=INDIRECT("USD")');
  77. $result = $sheet->getCell('E1')->getCalculatedValue();
  78. self::assertSame(300, $result);
  79. }
  80. public function testIndirectFile1(): void
  81. {
  82. $reader = new ReaderXlsx();
  83. $file = 'tests/data/Calculation/LookupRef/IndirectDefinedName.xlsx';
  84. $spreadsheet = $reader->load($file);
  85. $sheet = $spreadsheet->getActiveSheet();
  86. $result = $sheet->getCell('A5')->getCalculatedValue();
  87. self::assertSame(80, $result);
  88. $value = $sheet->getCell('A5')->getValue();
  89. self::assertSame('=INDIRECT("CURRENCY_EUR")', $value);
  90. }
  91. public function testIndirectFile2(): void
  92. {
  93. $reader = new ReaderXlsx();
  94. $file = 'tests/data/Calculation/LookupRef/IndirectFormulaSelection.xlsx';
  95. $spreadsheet = $reader->load($file);
  96. $sheet = $spreadsheet->getActiveSheet();
  97. $result = $sheet->getCell('A5')->getCalculatedValue();
  98. self::assertSame(100, $result);
  99. $value = $sheet->getCell('A5')->getValue();
  100. self::assertSame('=CURRENCY_SELECTOR', $value);
  101. $formula = $spreadsheet->getNamedFormula('CURRENCY_SELECTOR');
  102. if ($formula === null) {
  103. self::fail('Expected named formula was not defined');
  104. } else {
  105. self::assertSame('INDIRECT("CURRENCY_"&Sheet1!$D$1)', $formula->getFormula());
  106. }
  107. }
  108. public function testDeprecatedCall(): void
  109. {
  110. $sheet = $this->getSheet();
  111. $sheet->getCell('A1')->setValue('A2');
  112. $sheet->getCell('A2')->setValue('This is it');
  113. $result = \PhpOffice\PhpSpreadsheet\Calculation\LookupRef::INDIRECT('A2', $sheet->getCell('A1'));
  114. $result = \PhpOffice\PhpSpreadsheet\Calculation\Functions::flattenSingleValue($result);
  115. self::assertSame('This is it', $result);
  116. }
  117. /**
  118. * @param null|int|string $expectedResult
  119. *
  120. * @dataProvider providerRelative
  121. */
  122. public function testR1C1Relative($expectedResult, string $address): void
  123. {
  124. $sheet = $this->getSheet();
  125. $sheet->fromArray([
  126. ['a1', 'b1', 'c1'],
  127. ['a2', 'b2', 'c2'],
  128. ['a3', 'b3', 'c3'],
  129. ['a4', 'b4', 'c4'],
  130. ]);
  131. $sheet->getCell('B2')->setValue('=INDIRECT("' . $address . '", false)');
  132. self::assertSame($expectedResult, $sheet->getCell('B2')->getCalculatedValue());
  133. }
  134. public function providerRelative(): array
  135. {
  136. return [
  137. 'same row with bracket next column' => ['c2', 'R[]C[+1]'],
  138. 'same row without bracket next column' => ['c2', 'RC[+1]'],
  139. 'same row without bracket next column no plus sign' => ['c2', 'RC[1]'],
  140. 'same row previous column' => ['a2', 'RC[-1]'],
  141. 'previous row previous column' => ['a1', 'R[-1]C[-1]'],
  142. 'previous row same column with bracket' => ['b1', 'R[-1]C[]'],
  143. 'previous row same column without bracket' => ['b1', 'R[-1]C'],
  144. 'previous row next column' => ['c1', 'R[-1]C[+1]'],
  145. 'next row no plus sign previous column' => ['a3', 'R[1]C[-1]'],
  146. 'next row previous column' => ['a3', 'R[+1]C[-1]'],
  147. 'next row same column' => ['b3', 'R[+1]C'],
  148. 'next row next column' => ['c3', 'R[+1]C[+1]'],
  149. 'two rows down same column' => ['b4', 'R[+2]C'],
  150. 'invalid row' => ['#REF!', 'R[-2]C'],
  151. 'invalid column' => ['#REF!', 'RC[-2]'],
  152. 'circular reference' => [0, 'RC'], // matches Excel's treatment
  153. 'absolute row absolute column' => ['c2', 'R2C3'],
  154. 'absolute row relative column' => ['a2', 'R2C[-1]'],
  155. 'relative row absolute column lowercase' => ['a2', 'rc1'],
  156. 'uninitialized cell' => [null, 'RC[+2]'], // Excel result is 0
  157. ];
  158. }
  159. }