Skip to content

Commit 0c8db6e

Browse files
authored
Merge branch 'master' into issue1324
2 parents d1db784 + 8d8bc23 commit 0c8db6e

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

62 files changed

+752
-859
lines changed

CHANGELOG.md

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,11 @@ and this project adheres to [Semantic Versioning](https://semver.org). Thia is a
3636

3737
### Fixed
3838

39-
- Xlsx Writer eliminate xml:space from non-text nodes. [Issue #4542](https://github.com/PHPOffice/PhpSpreadsheet/issues/4542) [PR #4556](https://github.com/PHPOffice/PhpSpreadsheet/pull/4556)
40-
- Xlsx Writer eliminate xml:space from non-text nodes. [Issue #1324](https://github.com/PHPOffice/PhpSpreadsheet/issues/1324) [PR #4575](https://github.com/PHPOffice/PhpSpreadsheet/pull/4575)
39+
- Additional floating-point precision changes. [Issue #1324](https://github.com/PHPOffice/PhpSpreadsheet/issues/1324) [PR #4575](https://github.com/PHPOffice/PhpSpreadsheet/pull/4575)
40+
- Header/Footer images expand location. [Issue #484](https://github.com/PHPOffice/PhpSpreadsheet/issues/484) [Issue #1318](https://github.com/PHPOffice/PhpSpreadsheet/issues/1318) [PR #4572](https://github.com/PHPOffice/PhpSpreadsheet/pull/4572)
41+
- Create uninitialized cell if used in calculation. [Issue #4558](https://github.com/PHPOffice/PhpSpreadsheet/issues/4558) [Issue #4530](https://github.com/PHPOffice/PhpSpreadsheet/issues/4530) [PR #4565](https://github.com/PHPOffice/PhpSpreadsheet/pull/4565)
42+
- Shared/Date::isDateTime handle cells which calculate as arrays. [Issue #4557](https://github.com/PHPOffice/PhpSpreadsheet/issues/4557) [PR #4562](https://github.com/PHPOffice/PhpSpreadsheet/pull/4562)
43+
- Xlsx Writer eliminate xml:space from non-text nodes. [Issue #4542](https://github.com/PHPOffice/PhpSpreadsheet/issues/4542) [PR #4556](https://github.com/PHPOffice/PhpSpreadsheet/pull/4556)## 2025-07-23 - 4.5.0
4144

4245
## 2025-07-23 - 4.5.0
4346

composer.lock

Lines changed: 8 additions & 8 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

docs/topics/recipes.md

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -763,6 +763,17 @@ $spreadsheet->getActiveSheet()->getHeaderFooter()
763763
->setOddFooter('&L&B' . $spreadsheet->getProperties()->getTitle() . '&RPage &P of &N');
764764
```
765765

766+
<a id='setDifferent'></a>
767+
Notice the use of `oddHeader/Footer` above. This is, by default, the header used on all pages, not just the odd-numbered pages. You can specify a different header/footer for the first page and/or for even-numbered pages.
768+
```php
769+
$spreadsheet->getActiveSheet()->getHeaderFooter()
770+
->setDifferentFirst(true);
771+
// then as above except setFirstHeader/Footer rather than Odd
772+
$spreadsheet->getActiveSheet()->getHeaderFooter()
773+
->setDifferentOddEven(true);
774+
// then as above except setEvenHeader/Footer rather than Odd
775+
```
776+
766777
Substitution and formatting codes (starting with &) can be used inside
767778
headers and footers. There is no required order in which these codes
768779
must appear.
@@ -792,7 +803,7 @@ Code | Meaning
792803
`&C` | Code for "center section". When two or more occurrences of this section marker exist, the contents from all markers are concatenated, in the order of appearance, and placed into the center section.
793804
`&D` | Code for "date"
794805
`&T` | Code for "time"
795-
`&G` | Code for "picture as background" - Please make sure to add the image to the header/footer (see Tip for picture)
806+
`&G` | Code for "picture as background" - Please make sure to add the image to the header/footer (see [Tip for picture](#Tip-for-picture))
796807
`&U` | Code for "text single underline"
797808
`&E` | Code for "double underline"
798809
`&R` | Code for "right section". When two or more occurrences of this section marker exist, the contents from all markers are concatenated, in the order of appearance, and placed into the right section.
@@ -835,6 +846,7 @@ users may find it easier to rename test.xlsx to test.zip, unzip it, and
835846
inspect directly the contents of the relevant xl/worksheets/sheetX.xml
836847
to find the codes for header/footer.
837848

849+
<a id='Tip-for-picture'></a>
838850
**Tip for picture**
839851

840852
```php
@@ -844,22 +856,34 @@ $drawing->setPath('./images/PhpSpreadsheet_logo.png');
844856
$drawing->setHeight(36);
845857
$spreadsheet->getActiveSheet()
846858
->getHeaderFooter()
847-
->addImage($drawing, \PhpOffice\PhpSpreadsheet\Worksheet\HeaderFooter::IMAGE_HEADER_LEFT);
859+
->addImage(
860+
$drawing,
861+
\PhpOffice\PhpSpreadsheet\Worksheet\HeaderFooter::IMAGE_HEADER_LEFT
862+
);
848863
```
864+
If you want your image to be used only on the first page or only on even pages, use, for example, `HeaderFooter::IMAGE_FOOTER_CENTER_EVEN`.
865+
You must still call [`setDifferentFirst/Even`](#setDifferent) for this to work.
866+
This will work only for Xlsx.
849867

850868
### Setting printing breaks on a row or column
851869

852870
To set a print break, use the following code, which sets a row break on
853871
row 10.
854872

855873
```php
856-
$spreadsheet->getActiveSheet()->setBreak('A10', \PhpOffice\PhpSpreadsheet\Worksheet\Worksheet::BREAK_ROW);
874+
$spreadsheet->getActiveSheet()->setBreak(
875+
'A10',
876+
\PhpOffice\PhpSpreadsheet\Worksheet\Worksheet::BREAK_ROW
877+
);
857878
```
858879

859880
The following line of code sets a print break on column D:
860881

861882
```php
862-
$spreadsheet->getActiveSheet()->setBreak('D10', \PhpOffice\PhpSpreadsheet\Worksheet\Worksheet::BREAK_COLUMN);
883+
$spreadsheet->getActiveSheet()->setBreak(
884+
'D10',
885+
\PhpOffice\PhpSpreadsheet\Worksheet\Worksheet::BREAK_COLUMN
886+
);
863887
```
864888

865889
### Show/hide gridlines when printing

src/PhpSpreadsheet/Calculation/Calculation.php

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -207,10 +207,7 @@ public function __construct(?Spreadsheet $spreadsheet = null)
207207
public static function getInstance(?Spreadsheet $spreadsheet = null): self
208208
{
209209
if ($spreadsheet !== null) {
210-
$instance = $spreadsheet->getCalculationEngine();
211-
if (isset($instance)) {
212-
return $instance;
213-
}
210+
return $spreadsheet->getCalculationEngine();
214211
}
215212

216213
if (!self::$instance) {
@@ -220,6 +217,20 @@ public static function getInstance(?Spreadsheet $spreadsheet = null): self
220217
return self::$instance;
221218
}
222219

220+
/**
221+
* Intended for use only via a destructor.
222+
*
223+
* @internal
224+
*/
225+
public static function getInstanceOrNull(?Spreadsheet $spreadsheet = null): ?self
226+
{
227+
if ($spreadsheet !== null) {
228+
return $spreadsheet->getCalculationEngineOrNull();
229+
}
230+
231+
return null;
232+
}
233+
223234
/**
224235
* Flush the calculation cache for any existing instance of this class
225236
* but only if a Calculation instance exists.
@@ -1999,6 +2010,9 @@ private function processTokenStack(false|array $tokens, ?string $cellID = null,
19992010
$this->debugLog->writeDebugLog('Evaluating Cell %s in worksheet %s', $cellRef, $matches[2]);
20002011
if ($pCellParent !== null && $this->spreadsheet !== null) {
20012012
$cellSheet = $this->spreadsheet->getSheetByName($matches[2]);
2013+
if ($cellSheet && !$cellSheet->cellExists($cellRef)) {
2014+
$cellSheet->setCellValue($cellRef, null);
2015+
}
20022016
if ($cellSheet && $cellSheet->cellExists($cellRef)) {
20032017
$cellValue = $this->extractCellRange($cellRef, $this->spreadsheet->getSheetByName($matches[2]), false);
20042018
$cell->attach($pCellParent);
@@ -2503,7 +2517,7 @@ protected function raiseFormulaError(string $errorMessage, int $code = 0, ?Throw
25032517
*
25042518
* @return mixed[] Array of values in range if range contains more than one element. Otherwise, a single value is returned.
25052519
*/
2506-
public function extractCellRange(string &$range = 'A1', ?Worksheet $worksheet = null, bool $resetLog = true): array
2520+
public function extractCellRange(string &$range = 'A1', ?Worksheet $worksheet = null, bool $resetLog = true, bool $createCell = false): array
25072521
{
25082522
// Return value
25092523
/** @var mixed[][] */
@@ -2525,6 +2539,9 @@ public function extractCellRange(string &$range = 'A1', ?Worksheet $worksheet =
25252539
if (!isset($aReferences[1])) {
25262540
// Single cell in range
25272541
sscanf($aReferences[0], '%[A-Z]%d', $currentCol, $currentRow);
2542+
if ($createCell && $worksheet !== null && !$worksheet->cellExists($aReferences[0])) {
2543+
$worksheet->setCellValue($aReferences[0], null);
2544+
}
25282545
if ($worksheet !== null && $worksheet->cellExists($aReferences[0])) {
25292546
$temp = $worksheet->getCell($aReferences[0])->getCalculatedValue($resetLog);
25302547
if ($this->getInstanceArrayReturnType() === self::RETURN_ARRAY_AS_ARRAY) {
@@ -2541,6 +2558,9 @@ public function extractCellRange(string &$range = 'A1', ?Worksheet $worksheet =
25412558
foreach ($aReferences as $reference) {
25422559
// Extract range
25432560
sscanf($reference, '%[A-Z]%d', $currentCol, $currentRow);
2561+
if ($createCell && $worksheet !== null && !$worksheet->cellExists($reference)) {
2562+
$worksheet->setCellValue($reference, null);
2563+
}
25442564
if ($worksheet !== null && $worksheet->cellExists($reference)) {
25452565
$temp = $worksheet->getCell($reference)->getCalculatedValue($resetLog);
25462566
if ($this->getInstanceArrayReturnType() === self::RETURN_ARRAY_AS_ARRAY) {

src/PhpSpreadsheet/Calculation/Financial/Amortization.php

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -54,9 +54,7 @@ public static function AMORDEGRC(
5454
$salvage = Functions::flattenSingleValue($salvage);
5555
$period = Functions::flattenSingleValue($period);
5656
$rate = Functions::flattenSingleValue($rate);
57-
$basis = ($basis === null)
58-
? FinancialConstants::BASIS_DAYS_PER_YEAR_NASD
59-
: Functions::flattenSingleValue($basis);
57+
$basis = Functions::flattenSingleValue($basis) ?? FinancialConstants::BASIS_DAYS_PER_YEAR_NASD;
6058

6159
try {
6260
$cost = FinancialValidations::validateFloat($cost);
@@ -141,9 +139,7 @@ public static function AMORLINC(
141139
$salvage = Functions::flattenSingleValue($salvage);
142140
$period = Functions::flattenSingleValue($period);
143141
$rate = Functions::flattenSingleValue($rate);
144-
$basis = ($basis === null)
145-
? FinancialConstants::BASIS_DAYS_PER_YEAR_NASD
146-
: Functions::flattenSingleValue($basis);
142+
$basis = Functions::flattenSingleValue($basis) ?? FinancialConstants::BASIS_DAYS_PER_YEAR_NASD;
147143

148144
try {
149145
$cost = FinancialValidations::validateFloat($cost);

src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic.php

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,9 @@ public static function futureValue(
3838
): string|float {
3939
$rate = Functions::flattenSingleValue($rate);
4040
$numberOfPeriods = Functions::flattenSingleValue($numberOfPeriods);
41-
$payment = ($payment === null) ? 0.0 : Functions::flattenSingleValue($payment);
42-
$presentValue = ($presentValue === null) ? 0.0 : Functions::flattenSingleValue($presentValue);
43-
$type = ($type === null) ? FinancialConstants::PAYMENT_END_OF_PERIOD : Functions::flattenSingleValue($type);
41+
$payment = Functions::flattenSingleValue($payment) ?? 0.0;
42+
$presentValue = Functions::flattenSingleValue($presentValue) ?? 0.0;
43+
$type = Functions::flattenSingleValue($type) ?? FinancialConstants::PAYMENT_END_OF_PERIOD;
4444

4545
try {
4646
$rate = CashFlowValidations::validateRate($rate);
@@ -77,9 +77,9 @@ public static function presentValue(
7777
): string|float {
7878
$rate = Functions::flattenSingleValue($rate);
7979
$numberOfPeriods = Functions::flattenSingleValue($numberOfPeriods);
80-
$payment = ($payment === null) ? 0.0 : Functions::flattenSingleValue($payment);
81-
$futureValue = ($futureValue === null) ? 0.0 : Functions::flattenSingleValue($futureValue);
82-
$type = ($type === null) ? FinancialConstants::PAYMENT_END_OF_PERIOD : Functions::flattenSingleValue($type);
80+
$payment = Functions::flattenSingleValue($payment) ?? 0.0;
81+
$futureValue = Functions::flattenSingleValue($futureValue) ?? 0.0;
82+
$type = Functions::flattenSingleValue($type) ?? FinancialConstants::PAYMENT_END_OF_PERIOD;
8383

8484
try {
8585
$rate = CashFlowValidations::validateRate($rate);
@@ -122,8 +122,8 @@ public static function periods(
122122
$rate = Functions::flattenSingleValue($rate);
123123
$payment = Functions::flattenSingleValue($payment);
124124
$presentValue = Functions::flattenSingleValue($presentValue);
125-
$futureValue = ($futureValue === null) ? 0.0 : Functions::flattenSingleValue($futureValue);
126-
$type = ($type === null) ? FinancialConstants::PAYMENT_END_OF_PERIOD : Functions::flattenSingleValue($type);
125+
$futureValue = Functions::flattenSingleValue($futureValue) ?? 0.0;
126+
$type = Functions::flattenSingleValue($type) ?? FinancialConstants::PAYMENT_END_OF_PERIOD;
127127

128128
try {
129129
$rate = CashFlowValidations::validateRate($rate);

src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic/Cumulative.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ public static function interest(
4141
$presentValue = Functions::flattenSingleValue($presentValue);
4242
$start = Functions::flattenSingleValue($start);
4343
$end = Functions::flattenSingleValue($end);
44-
$type = ($type === null) ? FinancialConstants::PAYMENT_END_OF_PERIOD : Functions::flattenSingleValue($type);
44+
$type = Functions::flattenSingleValue($type) ?? FinancialConstants::PAYMENT_END_OF_PERIOD;
4545

4646
try {
4747
$rate = CashFlowValidations::validateRate($rate);
@@ -104,7 +104,7 @@ public static function principal(
104104
$presentValue = Functions::flattenSingleValue($presentValue);
105105
$start = Functions::flattenSingleValue($start);
106106
$end = Functions::flattenSingleValue($end);
107-
$type = ($type === null) ? FinancialConstants::PAYMENT_END_OF_PERIOD : Functions::flattenSingleValue($type);
107+
$type = Functions::flattenSingleValue($type) ?? FinancialConstants::PAYMENT_END_OF_PERIOD;
108108

109109
try {
110110
$rate = CashFlowValidations::validateRate($rate);

src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic/Interest.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ public static function payment(
4343
$numberOfPeriods = Functions::flattenSingleValue($numberOfPeriods);
4444
$presentValue = Functions::flattenSingleValue($presentValue);
4545
$futureValue = ($futureValue === null) ? 0.0 : Functions::flattenSingleValue($futureValue);
46-
$type = ($type === null) ? FinancialConstants::PAYMENT_END_OF_PERIOD : Functions::flattenSingleValue($type);
46+
$type = Functions::flattenSingleValue($type) ?? FinancialConstants::PAYMENT_END_OF_PERIOD;
4747

4848
try {
4949
$interestRate = CashFlowValidations::validateRate($interestRate);
@@ -160,9 +160,9 @@ public static function rate(
160160
$numberOfPeriods = Functions::flattenSingleValue($numberOfPeriods);
161161
$payment = Functions::flattenSingleValue($payment);
162162
$presentValue = Functions::flattenSingleValue($presentValue);
163-
$futureValue = ($futureValue === null) ? 0.0 : Functions::flattenSingleValue($futureValue);
164-
$type = ($type === null) ? FinancialConstants::PAYMENT_END_OF_PERIOD : Functions::flattenSingleValue($type);
165-
$guess = ($guess === null) ? 0.1 : Functions::flattenSingleValue($guess);
163+
$futureValue = Functions::flattenSingleValue($futureValue) ?? 0.0;
164+
$type = Functions::flattenSingleValue($type) ?? FinancialConstants::PAYMENT_END_OF_PERIOD;
165+
$guess = Functions::flattenSingleValue($guess) ?? 0.1;
166166

167167
try {
168168
$numberOfPeriods = CashFlowValidations::validateFloat($numberOfPeriods);

src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic/Payments.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,14 +27,14 @@ public static function annuity(
2727
mixed $interestRate,
2828
mixed $numberOfPeriods,
2929
mixed $presentValue,
30-
mixed $futureValue = 0,
30+
mixed $futureValue = 0.0,
3131
mixed $type = FinancialConstants::PAYMENT_END_OF_PERIOD
3232
): string|float {
3333
$interestRate = Functions::flattenSingleValue($interestRate);
3434
$numberOfPeriods = Functions::flattenSingleValue($numberOfPeriods);
3535
$presentValue = Functions::flattenSingleValue($presentValue);
36-
$futureValue = ($futureValue === null) ? 0.0 : Functions::flattenSingleValue($futureValue);
37-
$type = ($type === null) ? FinancialConstants::PAYMENT_END_OF_PERIOD : Functions::flattenSingleValue($type);
36+
$futureValue = Functions::flattenSingleValue($futureValue) ?? 0.0;
37+
$type = Functions::flattenSingleValue($type) ?? FinancialConstants::PAYMENT_END_OF_PERIOD;
3838

3939
try {
4040
$interestRate = CashFlowValidations::validateRate($interestRate);
@@ -83,7 +83,7 @@ public static function interestPayment(
8383
$numberOfPeriods = Functions::flattenSingleValue($numberOfPeriods);
8484
$presentValue = Functions::flattenSingleValue($presentValue);
8585
$futureValue = ($futureValue === null) ? 0.0 : Functions::flattenSingleValue($futureValue);
86-
$type = ($type === null) ? FinancialConstants::PAYMENT_END_OF_PERIOD : Functions::flattenSingleValue($type);
86+
$type = Functions::flattenSingleValue($type) ?? FinancialConstants::PAYMENT_END_OF_PERIOD;
8787

8888
try {
8989
$interestRate = CashFlowValidations::validateRate($interestRate);

0 commit comments

Comments
 (0)