diff --git a/CHANGELOG.md b/CHANGELOG.md
index 73e90dc6..67dbe238 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](https://semver.org).
## Unreleased - TBD
+- Fixed `ReferenceHelper@insertNewBefore` behavior when removing column before last column with null value
+
### Added
- Improved support for passing of array arguments to Excel function implementations to return array results (where appropriate). [Issue #2551](https://github.com/PHPOffice/PhpSpreadsheet/issues/2551)
diff --git a/samples/Basic/02_Types.php b/samples/Basic/02_Types.php
index 79f109f5..965071b8 100644
--- a/samples/Basic/02_Types.php
+++ b/samples/Basic/02_Types.php
@@ -1,5 +1,6 @@
getActiveSheet()
$spreadsheet->getActiveSheet()
->setCellValue('C18', '=HYPERLINK("mailto:abc@def.com","abc@def.com")');
+$spreadsheet->getActiveSheet()
+ ->setCellValue('A20', 'String')
+ ->setCellValue('B20', 'inline')
+ ->setCellValueExplicit('C20', 'This will not be added to sharedStrings.xml', DataType::TYPE_INLINE);
+
$spreadsheet->getActiveSheet()
->getColumnDimension('B')
->setAutoSize(true);
diff --git a/src/PhpSpreadsheet/Reader/Xlsx.php b/src/PhpSpreadsheet/Reader/Xlsx.php
index bf696a60..f7625d5e 100644
--- a/src/PhpSpreadsheet/Reader/Xlsx.php
+++ b/src/PhpSpreadsheet/Reader/Xlsx.php
@@ -1691,13 +1691,17 @@ class Xlsx extends BaseReader
} else {
$objText = $value->createTextRun(StringHelper::controlCharacterOOXML2PHP((string) $run->t));
- $attr = $run->rPr->rFont->attributes();
- if (isset($attr['val'])) {
- $objText->getFont()->setName((string) $attr['val']);
+ if (isset($run->rPr->rFont)) {
+ $attr = $run->rPr->rFont->attributes();
+ if (isset($attr['val'])) {
+ $objText->getFont()->setName((string) $attr['val']);
+ }
}
- $attr = $run->rPr->sz->attributes();
- if (isset($attr['val'])) {
- $objText->getFont()->setSize((float) $attr['val']);
+ if (isset($run->rPr->sz)) {
+ $attr = $run->rPr->sz->attributes();
+ if (isset($attr['val'])) {
+ $objText->getFont()->setSize((float) $attr['val']);
+ }
}
if (isset($run->rPr->color)) {
$objText->getFont()->setColor(new Color($this->styleReader->readColor($run->rPr->color)));
diff --git a/src/PhpSpreadsheet/ReferenceHelper.php b/src/PhpSpreadsheet/ReferenceHelper.php
index 0d72b305..98c4807a 100644
--- a/src/PhpSpreadsheet/ReferenceHelper.php
+++ b/src/PhpSpreadsheet/ReferenceHelper.php
@@ -398,6 +398,26 @@ class ReferenceHelper
}
}
+ // Find missing coordinates. This is important when inserting column before the last column
+ $missingCoordinates = array_filter(
+ array_map(function ($row) use ($highestColumn) {
+ return $highestColumn . $row;
+ }, range(1, $highestRow)),
+ function ($coordinate) use ($allCoordinates) {
+ return !in_array($coordinate, $allCoordinates);
+ }
+ );
+
+ // Create missing cells with null values
+ if (!empty($missingCoordinates)) {
+ foreach ($missingCoordinates as $coordinate) {
+ $worksheet->createNewCell($coordinate);
+ }
+
+ // Refresh all coordinates
+ $allCoordinates = $worksheet->getCoordinates();
+ }
+
// Loop through cells, bottom-up, and change cell coordinate
if ($remove) {
// It's faster to reverse and pop than to use unshift, especially with large cell collections
diff --git a/src/PhpSpreadsheet/Worksheet/Worksheet.php b/src/PhpSpreadsheet/Worksheet/Worksheet.php
index 51cf3c52..362f20f0 100644
--- a/src/PhpSpreadsheet/Worksheet/Worksheet.php
+++ b/src/PhpSpreadsheet/Worksheet/Worksheet.php
@@ -1291,7 +1291,7 @@ class Worksheet implements IComparable
*
* @return Cell Cell that was created
*/
- private function createNewCell($coordinate)
+ public function createNewCell($coordinate)
{
$cell = new Cell(null, DataType::TYPE_NULL, $this);
$this->cellCollection->add($coordinate, $cell);
diff --git a/src/PhpSpreadsheet/Writer/Xls/Worksheet.php b/src/PhpSpreadsheet/Writer/Xls/Worksheet.php
index 2387ceb0..979d3cb7 100644
--- a/src/PhpSpreadsheet/Writer/Xls/Worksheet.php
+++ b/src/PhpSpreadsheet/Writer/Xls/Worksheet.php
@@ -433,6 +433,7 @@ class Worksheet extends BIFFwriter
} else {
switch ($cell->getDatatype()) {
case DataType::TYPE_STRING:
+ case DataType::TYPE_INLINE:
case DataType::TYPE_NULL:
if ($cVal === '' || $cVal === null) {
$this->writeBlank($row, $column, $xfIndex);
diff --git a/src/PhpSpreadsheet/Writer/Xlsx/Worksheet.php b/src/PhpSpreadsheet/Writer/Xlsx/Worksheet.php
index 86f966e7..ab390a90 100644
--- a/src/PhpSpreadsheet/Writer/Xlsx/Worksheet.php
+++ b/src/PhpSpreadsheet/Writer/Xlsx/Worksheet.php
@@ -1189,10 +1189,12 @@ class Worksheet extends WriterPart
{
$objWriter->writeAttribute('t', $mappedType);
if (!$cellValue instanceof RichText) {
+ $objWriter->startElement('is');
$objWriter->writeElement(
't',
StringHelper::controlCharacterPHP2OOXML(htmlspecialchars($cellValue, Settings::htmlEntityFlags()))
);
+ $objWriter->endElement();
} elseif ($cellValue instanceof RichText) {
$objWriter->startElement('is');
$this->getParentWriter()->getWriterPartstringtable()->writeRichText($objWriter, $cellValue);
diff --git a/tests/PhpSpreadsheetTests/Reader/Xlsx/Issue2542Test.php b/tests/PhpSpreadsheetTests/Reader/Xlsx/Issue2542Test.php
new file mode 100644
index 00000000..ad970001
--- /dev/null
+++ b/tests/PhpSpreadsheetTests/Reader/Xlsx/Issue2542Test.php
@@ -0,0 +1,47 @@
+Factor group
+(for Rental items only)', $data);
+ }
+ }
+
+ public function testIssue2542(): void
+ {
+ $filename = self::$testbook;
+ $reader = new Xlsx();
+ $spreadsheet = $reader->load($filename);
+ $sheet = $spreadsheet->getActiveSheet();
+ $value = $sheet->getCell('P1')->getValue();
+ if ($value instanceof RichText) {
+ self::assertSame("Factor group\n(for Rental items only)", $value->getPlainText());
+ } else {
+ self::fail('Cell P1 is not RichText');
+ }
+ $spreadsheet->disconnectWorksheets();
+ }
+}
diff --git a/tests/PhpSpreadsheetTests/ReferenceHelperTest.php b/tests/PhpSpreadsheetTests/ReferenceHelperTest.php
index 874dbfb5..2c016b0b 100644
--- a/tests/PhpSpreadsheetTests/ReferenceHelperTest.php
+++ b/tests/PhpSpreadsheetTests/ReferenceHelperTest.php
@@ -149,4 +149,32 @@ class ReferenceHelperTest extends TestCase
self::assertSame($oldValue, $newValue);
self::assertSame($oldDataType, $newDataType);
}
+
+ public function testRemoveColumnShiftsCorrectColumnValueIntoRemovedColumnCoordinates(): void
+ {
+ $spreadsheet = new Spreadsheet();
+ $sheet = $spreadsheet->getActiveSheet();
+ $sheet->fromArray([
+ ['a1', 'b1', 'c1'],
+ ['a2', 'b2', null],
+ ]);
+
+ $cells = $sheet->toArray();
+ self::assertSame('a1', $cells[0][0]);
+ self::assertSame('b1', $cells[0][1]);
+ self::assertSame('c1', $cells[0][2]);
+ self::assertSame('a2', $cells[1][0]);
+ self::assertSame('b2', $cells[1][1]);
+ self::assertNull($cells[1][2]);
+
+ $sheet->removeColumn('B');
+
+ $cells = $sheet->toArray();
+ self::assertSame('a1', $cells[0][0]);
+ self::assertSame('c1', $cells[0][1]);
+ self::assertArrayNotHasKey(2, $cells[0]);
+ self::assertSame('a2', $cells[1][0]);
+ self::assertNull($cells[1][1]);
+ self::assertArrayNotHasKey(2, $cells[1]);
+ }
}
diff --git a/tests/data/Reader/XLSX/issue.2542.xlsx b/tests/data/Reader/XLSX/issue.2542.xlsx
new file mode 100644
index 00000000..85faa63a
Binary files /dev/null and b/tests/data/Reader/XLSX/issue.2542.xlsx differ