Skip to content

Commit f5b4308

Browse files
author
MarkBaker
committed
Merge branch 'master' into CalculationEngine-Array-Formulae-Initial-Work
2 parents acfd752 + 54d82cd commit f5b4308

30 files changed

+464
-108
lines changed

docs/topics/reading-and-writing-to-file.md

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -436,7 +436,14 @@ You can read a .csv file using the following code:
436436

437437
```php
438438
$reader = new \PhpOffice\PhpSpreadsheet\Reader\Csv();
439-
$spreadsheet = $reader->load("sample.csv");
439+
$spreadsheet = $reader->load('sample.csv');
440+
```
441+
442+
You can also treat a string as if it were the contents of a CSV file as follows:
443+
444+
```php
445+
$reader = new \PhpOffice\PhpSpreadsheet\Reader\Csv();
446+
$spreadsheet = $reader->loadSpreadsheetFromString($data);
440447
```
441448

442449
#### Setting CSV options

phpstan-baseline.neon

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -320,11 +320,6 @@ parameters:
320320
count: 1
321321
path: src/PhpSpreadsheet/Calculation/Engineering/ErfC.php
322322

323-
-
324-
message: "#^Parameter \\#1 \\$callback of function set_error_handler expects \\(callable\\(int, string, string, int, array\\)\\: bool\\)\\|null, array\\{'PhpOffice\\\\\\\\PhpSpreadsheet\\\\\\\\Calculation\\\\\\\\Exception', 'errorHandlerCallback'\\} given\\.$#"
325-
count: 1
326-
path: src/PhpSpreadsheet/Calculation/ExceptionHandler.php
327-
328323
-
329324
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\:\\:ISPMT\\(\\) has no return type specified\\.$#"
330325
count: 1
@@ -4202,7 +4197,7 @@ parameters:
42024197

42034198
-
42044199
message: "#^Strict comparison using \\=\\=\\= between string and null will always evaluate to false\\.$#"
4205-
count: 1
4200+
count: 2
42064201
path: src/PhpSpreadsheet/Worksheet/Worksheet.php
42074202

42084203
-

phpstan-conditional.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,13 @@
4646
'path' => __DIR__ . '/src/PhpSpreadsheet/Shared/StringHelper.php',
4747
'count' => 1,
4848
];
49+
} else {
50+
// Flagged in Php8+ - unsure how to correct code
51+
$config['parameters']['ignoreErrors'][] = [
52+
'message' => '#^Binary operation "/" between float and array[|]float[|]int[|]string results in an error.#',
53+
'path' => __DIR__ . '/src/PhpSpreadsheet/Calculation/MathTrig/Combinations.php',
54+
'count' => 2,
55+
];
4956
}
5057

5158
return $config;

samples/Basic/27_Images_Html_Pdf.php

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
<?php
2+
3+
use PhpOffice\PhpSpreadsheet\IOFactory;
4+
use PhpOffice\PhpSpreadsheet\Reader\Xlsx as XlsxReader;
5+
use PhpOffice\PhpSpreadsheet\Shared\File;
6+
use PhpOffice\PhpSpreadsheet\Worksheet\PageSetup;
7+
use PhpOffice\PhpSpreadsheet\Writer\Pdf\Mpdf;
8+
use PhpOffice\PhpSpreadsheet\Writer\Xlsx as XlsxWriter;
9+
10+
require __DIR__ . '/../Header.php';
11+
12+
// Read from Xls (.xls) template
13+
$helper->log('Load Xlsx template file');
14+
$reader = IOFactory::createReader('Xls');
15+
$initialSpreadsheet = $reader->load(__DIR__ . '/../templates/27template.xls');
16+
17+
$xlsxFile = File::temporaryFilename();
18+
$writer = new XlsxWriter($initialSpreadsheet);
19+
$helper->log('Save as Xlsx');
20+
$writer->save($xlsxFile);
21+
$initialSpreadsheet->disconnectWorksheets();
22+
$reader2 = new XlsxReader();
23+
$helper->log('Load Xlsx');
24+
$spreadsheet = $reader2->load($xlsxFile);
25+
26+
$helper->log('Hide grid lines');
27+
$spreadsheet->getActiveSheet()->setShowGridLines(false);
28+
29+
$helper->log('Set orientation to landscape');
30+
$spreadsheet->getActiveSheet()->getPageSetup()->setOrientation(PageSetup::ORIENTATION_LANDSCAPE);
31+
32+
$className = Mpdf::class;
33+
$helper->log("Write to PDF format using {$className}, and to Html");
34+
IOFactory::registerWriter('Pdf', $className);
35+
36+
// Save
37+
$helper->write($spreadsheet, __FILE__, ['Pdf', 'Html']);
38+
unlink($xlsxFile);
39+
$spreadsheet->disconnectWorksheets();

src/PhpSpreadsheet/Calculation/ArrayEnabled.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ private static function initialiseHelper($arguments): void
2020
if (self::$arrayArgumentHelper === null) {
2121
self::$arrayArgumentHelper = new ArrayArgumentHelper();
2222
}
23-
self::$arrayArgumentHelper->initialise($arguments ?: []);
23+
self::$arrayArgumentHelper->initialise(($arguments === false) ? [] : $arguments);
2424
}
2525

2626
/**

src/PhpSpreadsheet/Calculation/ExceptionHandler.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@ class ExceptionHandler
99
*/
1010
public function __construct()
1111
{
12-
set_error_handler([Exception::class, 'errorHandlerCallback'], E_ALL);
12+
/** @var callable */
13+
$callable = [Exception::class, 'errorHandlerCallback'];
14+
set_error_handler($callable, E_ALL);
1315
}
1416

1517
/**

src/PhpSpreadsheet/Cell/AddressHelper.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -118,17 +118,17 @@ public static function convertToR1C1(
118118
throw new Exception('Invalid A1-format Cell Reference');
119119
}
120120

121-
$columnId = Coordinate::columnIndexFromString($cellReference['col_ref']);
122-
if ($cellReference['absolute_col'] === '$') {
121+
if ($cellReference['col'][0] === '$') {
123122
// Column must be absolute address
124123
$currentColumnNumber = null;
125124
}
125+
$columnId = Coordinate::columnIndexFromString(ltrim($cellReference['col'], '$'));
126126

127-
$rowId = (int) $cellReference['row_ref'];
128-
if ($cellReference['absolute_row'] === '$') {
127+
if ($cellReference['row'][0] === '$') {
129128
// Row must be absolute address
130129
$currentRowNumber = null;
131130
}
131+
$rowId = (int) ltrim($cellReference['row'], '$');
132132

133133
if ($currentRowNumber !== null) {
134134
if ($rowId === $currentRowNumber) {

src/PhpSpreadsheet/Cell/CellAddress.php

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,7 @@ class CellAddress
3535
public function __construct(string $cellAddress, ?Worksheet $worksheet = null)
3636
{
3737
$this->cellAddress = str_replace('$', '', $cellAddress);
38-
[$this->columnName, $rowId] = Coordinate::coordinateFromString($cellAddress);
39-
$this->rowId = (int) $rowId;
40-
$this->columnId = Coordinate::columnIndexFromString($this->columnName);
38+
[$this->columnId, $this->rowId, $this->columnName] = Coordinate::indexesFromString($this->cellAddress);
4139
$this->worksheet = $worksheet;
4240
}
4341

src/PhpSpreadsheet/Cell/Coordinate.php

Lines changed: 24 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
*/
1414
abstract class Coordinate
1515
{
16-
public const A1_COORDINATE_REGEX = '/^(?<absolute_col>\$?)(?<col_ref>[A-Z]{1,3})(?<absolute_row>\$?)(?<row_ref>\d{1,7})$/i';
16+
public const A1_COORDINATE_REGEX = '/^(?<col>\$?[A-Z]{1,3})(?<row>\$?\d{1,7})$/i';
1717

1818
/**
1919
* Default range variable constant.
@@ -32,7 +32,7 @@ abstract class Coordinate
3232
public static function coordinateFromString($cellAddress)
3333
{
3434
if (preg_match(self::A1_COORDINATE_REGEX, $cellAddress, $matches)) {
35-
return [$matches['absolute_col'] . $matches['col_ref'], $matches['absolute_row'] . $matches['row_ref']];
35+
return [$matches['col'], $matches['row']];
3636
} elseif (self::coordinateIsRange($cellAddress)) {
3737
throw new Exception('Cell coordinate string can not be a range of cells');
3838
} elseif ($cellAddress == '') {
@@ -276,35 +276,42 @@ public static function columnIndexFromString($columnAddress)
276276
if (isset($indexCache[$columnAddress])) {
277277
return $indexCache[$columnAddress];
278278
}
279-
// It's surprising how costly the strtoupper() and ord() calls actually are, so we use a lookup array rather than use ord()
280-
// and make it case insensitive to get rid of the strtoupper() as well. Because it's a static, there's no significant
281-
// memory overhead either
279+
// It's surprising how costly the strtoupper() and ord() calls actually are, so we use a lookup array
280+
// rather than use ord() and make it case insensitive to get rid of the strtoupper() as well.
281+
// Because it's a static, there's no significant memory overhead either.
282282
static $columnLookup = [
283-
'A' => 1, 'B' => 2, 'C' => 3, 'D' => 4, 'E' => 5, 'F' => 6, 'G' => 7, 'H' => 8, 'I' => 9, 'J' => 10, 'K' => 11, 'L' => 12, 'M' => 13,
284-
'N' => 14, 'O' => 15, 'P' => 16, 'Q' => 17, 'R' => 18, 'S' => 19, 'T' => 20, 'U' => 21, 'V' => 22, 'W' => 23, 'X' => 24, 'Y' => 25, 'Z' => 26,
285-
'a' => 1, 'b' => 2, 'c' => 3, 'd' => 4, 'e' => 5, 'f' => 6, 'g' => 7, 'h' => 8, 'i' => 9, 'j' => 10, 'k' => 11, 'l' => 12, 'm' => 13,
286-
'n' => 14, 'o' => 15, 'p' => 16, 'q' => 17, 'r' => 18, 's' => 19, 't' => 20, 'u' => 21, 'v' => 22, 'w' => 23, 'x' => 24, 'y' => 25, 'z' => 26,
283+
'A' => 1, 'B' => 2, 'C' => 3, 'D' => 4, 'E' => 5, 'F' => 6, 'G' => 7, 'H' => 8, 'I' => 9, 'J' => 10,
284+
'K' => 11, 'L' => 12, 'M' => 13, 'N' => 14, 'O' => 15, 'P' => 16, 'Q' => 17, 'R' => 18, 'S' => 19,
285+
'T' => 20, 'U' => 21, 'V' => 22, 'W' => 23, 'X' => 24, 'Y' => 25, 'Z' => 26,
286+
'a' => 1, 'b' => 2, 'c' => 3, 'd' => 4, 'e' => 5, 'f' => 6, 'g' => 7, 'h' => 8, 'i' => 9, 'j' => 10,
287+
'k' => 11, 'l' => 12, 'm' => 13, 'n' => 14, 'o' => 15, 'p' => 16, 'q' => 17, 'r' => 18, 's' => 19,
288+
't' => 20, 'u' => 21, 'v' => 22, 'w' => 23, 'x' => 24, 'y' => 25, 'z' => 26,
287289
];
288290

289-
// We also use the language construct isset() rather than the more costly strlen() function to match the length of $columnAddress
290-
// for improved performance
291+
// We also use the language construct isset() rather than the more costly strlen() function to match the
292+
// length of $columnAddress for improved performance
291293
if (isset($columnAddress[0])) {
292294
if (!isset($columnAddress[1])) {
293295
$indexCache[$columnAddress] = $columnLookup[$columnAddress];
294296

295297
return $indexCache[$columnAddress];
296298
} elseif (!isset($columnAddress[2])) {
297-
$indexCache[$columnAddress] = $columnLookup[$columnAddress[0]] * 26 + $columnLookup[$columnAddress[1]];
299+
$indexCache[$columnAddress] = $columnLookup[$columnAddress[0]] * 26
300+
+ $columnLookup[$columnAddress[1]];
298301

299302
return $indexCache[$columnAddress];
300303
} elseif (!isset($columnAddress[3])) {
301-
$indexCache[$columnAddress] = $columnLookup[$columnAddress[0]] * 676 + $columnLookup[$columnAddress[1]] * 26 + $columnLookup[$columnAddress[2]];
304+
$indexCache[$columnAddress] = $columnLookup[$columnAddress[0]] * 676
305+
+ $columnLookup[$columnAddress[1]] * 26
306+
+ $columnLookup[$columnAddress[2]];
302307

303308
return $indexCache[$columnAddress];
304309
}
305310
}
306311

307-
throw new Exception('Column string index can not be ' . ((isset($columnAddress[0])) ? 'longer than 3 characters' : 'empty'));
312+
throw new Exception(
313+
'Column string index can not be ' . ((isset($columnAddress[0])) ? 'longer than 3 characters' : 'empty')
314+
);
308315
}
309316

310317
/**
@@ -317,14 +324,15 @@ public static function columnIndexFromString($columnAddress)
317324
public static function stringFromColumnIndex($columnIndex)
318325
{
319326
static $indexCache = [];
327+
static $lookupCache = ' ABCDEFGHIJKLMNOPQRSTUVWXYZ';
320328

321329
if (!isset($indexCache[$columnIndex])) {
322330
$indexValue = $columnIndex;
323-
$base26 = null;
331+
$base26 = '';
324332
do {
325333
$characterValue = ($indexValue % 26) ?: 26;
326334
$indexValue = ($indexValue - $characterValue) / 26;
327-
$base26 = chr($characterValue + 64) . ($base26 ?: '');
335+
$base26 = $lookupCache[$characterValue] . $base26;
328336
} while ($indexValue > 0);
329337
$indexCache[$columnIndex] = $base26;
330338
}

src/PhpSpreadsheet/Helper/Html.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -795,7 +795,7 @@ protected function parseTextNode(DOMText $textNode): void
795795
$domText = preg_replace(
796796
'/\s+/u',
797797
' ',
798-
str_replace(["\r", "\n"], ' ', $textNode->nodeValue ?: '')
798+
str_replace(["\r", "\n"], ' ', $textNode->nodeValue ?? '')
799799
);
800800
$this->stringData .= $domText;
801801
$this->buildTextRun();

0 commit comments

Comments
 (0)