Repository: PHPOffice/PhpSpreadsheet (php)

Issue:
Bug in ReferenceHelper::duplicateStylesByRow()
This is:

```
- [x] a bug report
- [ ] a feature request
- [ ] **not** a usage question (ask them on https://stackoverflow.com/questions/tagged/phpspreadsheet or https://gitter.im/PHPOffice/PhpSpreadsheet)
```

### What is the current behavior?

When trying to insert a large amount of rows via `Worksheet::insertNewRowBefore()` it will throw an exception saying something like `Invalid cell coordinate AAAA1`. Tracing the issue via stack trace showed that there is a bug in `ReferenceHelper::duplicateStylesByRow()`:

````
    private function duplicateStylesByRow(Worksheet $worksheet, int $beforeColumn, int $beforeRow, string $highestColumn, int $numberOfRows): void
    {
        $highestColumnIndex = Coordinate::columnIndexFromString($highestColumn);
        for ($i = $beforeColumn; $i <= $highestColumnIndex; ++$i) {
            // Style
            $coordinate = Coordinate::stringFromColumnIndex($i) . ($beforeRow - 1);
            if ($worksheet->cellExists($coordinate)) {
                $xfIndex = $worksheet->getCell($coordinate)->getXfIndex();
                for ($j = $beforeRow; $j <= $beforeRow - 1 + $numberOfRows; ++$j) {
                    if (!empty($xfIndex) || $worksheet->cellExists([$j, $i])) {
                        $worksheet->getCell(Coordinate::stringFromColumnIndex($i) . $j)->setXfIndex($xfIndex);
                    }
                }
            }
        }
    }

````

The portion where it calls `$worksheet->cellExists([$j, $i])` swaps the column and row numbers. It should be the other way around like `$worksheet->cellExists([$i, $j])` because the iteration is over i=column and j=row.

Maybe the bug comes from the similar function `ReferenceHelper::duplicateStylesByColumn()` where this exact same line exists but there it is correct because the iteration is over j=column and i=row. 

### What are the steps to reproduce?

Tried to recreate a piece of sample code but did not get it done in a reasonable amount of time because it also depends on the Excel file and on the XfIndex (don't know what that is) of the cell. But the error is pretty obvious just looking at the code.

### What features do you think are causing the issue

- [ ] Reader
- [ ] Writer
- [ ] Styles
- [ ] Data Validations
- [ ] Formula Calculations
- [ ] Charts
- [ ] AutoFilter
- [ ] Form Elements

### Does an issue affect all spreadsheet file formats? If not, which formats are affected?

Can't say.

### Which versions of PhpSpreadsheet and PHP are affected?

Our version is 2.2.2, but looking at the code base at Github it is still present in the current version.


Pull request description:
Swapped Row and Column Indexes in ReferenceHelper
Fix #4246. This can cause an Exception in unusual circumstances.

This is:

- [x] a bugfix
- [ ] a new feature
- [ ] refactoring
- [ ] additional unit tests

Checklist:

- [x] Changes are covered by unit tests
  - [ ] Changes are covered by existing unit tests
  - [x] New unit tests have been added
- [x] Code style is respected
- [x] Commit message explains **why** the change is made (see https://github.com/erlang/otp/wiki/Writing-good-commit-messages)
- [ ] CHANGELOG.md contains a short summary of the change and a link to the pull request if applicable
- [ ] Documentation is updated as necessary

### Why this change is needed?

Provide an explanation of why this change is needed, with links to any Issues (if appropriate).
If this is a bugfix or a new feature, and there are no existing Issues, then please also create an issue that will make it easier to track progress with this PR.


Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index dd265511f..c5753337b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -25,6 +25,7 @@ and this project adheres to [Semantic Versioning](https://semver.org).
 
 ### Fixed
 
+- Swapped row and column indexes in ReferenceHelper. [Issue #4246](https://github.com/PHPOffice/PhpSpreadsheet/issues/4246) [PR #4247](https://github.com/PHPOffice/PhpSpreadsheet/pull/4247)
 - Fix minor break handling drawings. [Issue #4241](https://github.com/PHPOffice/PhpSpreadsheet/issues/4241) [PR #4244](https://github.com/PHPOffice/PhpSpreadsheet/pull/4244)
 - Ignore cell formatting when the format is a single @. [Issue #4242](https://github.com/PHPOffice/PhpSpreadsheet/issues/4242) [PR #4243](https://github.com/PHPOffice/PhpSpreadsheet/pull/4243)
 
diff --git a/src/PhpSpreadsheet/ReferenceHelper.php b/src/PhpSpreadsheet/ReferenceHelper.php
index afcfa016e..dfcea10e4 100644
--- a/src/PhpSpreadsheet/ReferenceHelper.php
+++ b/src/PhpSpreadsheet/ReferenceHelper.php
@@ -1215,7 +1215,7 @@ class ReferenceHelper
             if ($worksheet->cellExists($coordinate)) {
                 $xfIndex = $worksheet->getCell($coordinate)->getXfIndex();
                 for ($j = $beforeRow; $j <= $beforeRow - 1 + $numberOfRows; ++$j) {
-                    if (!empty($xfIndex) || $worksheet->cellExists([$j, $i])) {
+                    if (!empty($xfIndex) || $worksheet->cellExists([$i, $j])) {
                         $worksheet->getCell(Coordinate::stringFromColumnIndex($i) . $j)->setXfIndex($xfIndex);
                     }
                 }


Test patch:
diff --git a/tests/PhpSpreadsheetTests/ReferenceHelper5Test.php b/tests/PhpSpreadsheetTests/ReferenceHelper5Test.php
new file mode 100644
index 000000000..bdb658896
--- /dev/null
+++ b/tests/PhpSpreadsheetTests/ReferenceHelper5Test.php
@@ -0,0 +1,45 @@
+<?php
+
+declare(strict_types=1);
+
+namespace PhpOffice\PhpSpreadsheetTests;
+
+use PhpOffice\PhpSpreadsheet\Spreadsheet;
+use PHPUnit\Framework\TestCase;
+
+class ReferenceHelper5Test extends TestCase
+{
+    public function testIssue4246(): void
+    {
+        // code below would have thrown exception because
+        // row and column were swapped in code
+        $spreadsheet = new Spreadsheet();
+        $sheet = $spreadsheet->getActiveSheet();
+        $row = 987654;
+        $rowMinus1 = $row - 1;
+        $rowPlus1 = $row + 1;
+        $sheet->getCell("A$rowMinus1")->setValue(1);
+        $sheet->getCell("B$rowMinus1")->setValue(2);
+        $sheet->getCell("C$rowMinus1")->setValue(3);
+        $sheet->getStyle("A$rowMinus1")->getFont()->setBold(true);
+        $sheet->getCell("A$row")->setValue(1);
+        $sheet->getCell("B$row")->setValue(2);
+        $sheet->getCell("C$row")->setValue(3);
+        $sheet->getStyle("B$row")->getFont()->setBold(true);
+
+        $sheet->insertNewRowBefore($row);
+        self::assertTrue(
+            $sheet->getStyle("A$row")->getFont()->getBold()
+        );
+        self::assertFalse(
+            $sheet->getStyle("B$row")->getFont()->getBold()
+        );
+        self::assertFalse(
+            $sheet->getStyle("A$rowPlus1")->getFont()->getBold()
+        );
+        self::assertTrue(
+            $sheet->getStyle("B$rowPlus1")->getFont()->getBold()
+        );
+        $spreadsheet->disconnectWorksheets();
+    }
+}