Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Excel Dynamic Arrays (Avoid Adding At-Signs to Formulas) #3962

Merged
merged 42 commits into from
Aug 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
be25c44
WIP Excel Adding At-Signs to Functions
oleibman Mar 27, 2024
b53a4b7
Xlsx Reader Use Dimensions from Functions With Array Results
oleibman Apr 17, 2024
61f24ca
Sample Submitted by @jr212
oleibman Apr 19, 2024
74f312b
Merge branch 'master' into atsign
oleibman Apr 19, 2024
c78888c
Merge branch 'master' into atsign
oleibman May 31, 2024
5e7ebf3
Merge branch 'master' into atsign
oleibman Jun 3, 2024
b79cd20
Merge branch 'master' into atsign
oleibman Jun 5, 2024
08ba00b
Populate Rest of Array Cells, UNIQUE Changes
oleibman Jun 6, 2024
856a00b
Formatting
oleibman Jun 6, 2024
1b21984
Incorrect Case for Filename
oleibman Jun 6, 2024
47481c6
More Formatting
oleibman Jun 6, 2024
6b5bf84
Still More Formatting
oleibman Jun 6, 2024
3daac0a
Add TODO Note
oleibman Jun 6, 2024
ef176f3
Excel Handle Array Functions as Dynamic Rather than CSE
oleibman Jun 10, 2024
846fec7
Minor Performance Improvements
oleibman Jun 10, 2024
ad2194d
CONCATENATE Changes, and Csv/Html/Ods Support
oleibman Jun 14, 2024
784e8a0
Drop Some Dead Code
oleibman Jun 14, 2024
d770012
Spills
oleibman Jun 17, 2024
8609b78
Eliminate Dead Code
oleibman Jun 17, 2024
2c9e2e2
Spill Operator
oleibman Jun 20, 2024
0b471ef
Dead Code, and 1 Static Call to Non-Static
oleibman Jun 20, 2024
3a690a7
SINGLE Function, and Gnumeric
oleibman Jun 21, 2024
ef2b5b9
Mostly Docs and Tests
oleibman Jun 22, 2024
fed7a32
Dead Code
oleibman Jun 22, 2024
2076a07
Minor Tweaks
oleibman Jun 23, 2024
b051d49
Use CELL("width") As Another Unimplemented Array Function
oleibman Jun 30, 2024
1253f35
Resolve Merge Conflict
oleibman Jun 30, 2024
edf7f71
Merge branch 'master' into atsign
oleibman Jun 30, 2024
5295704
Merge branch 'master' into atsign
oleibman Jul 1, 2024
98ba95e
Update features-cross-reference.md
oleibman Jul 5, 2024
b22d1f5
Merge branch 'master' into atsign
oleibman Jul 7, 2024
5b18dcf
Shot Myself in Foot
oleibman Jul 8, 2024
fda4855
Anchor Cell Without Spill
oleibman Jul 10, 2024
b00dd47
Instance Variable for Array Return Type
oleibman Jul 10, 2024
a405ca0
Valid Scrutinizer Messages
oleibman Jul 10, 2024
a084e7d
More Scrutinizer
oleibman Jul 10, 2024
312cd5a
Merge branch 'master' into atsign
oleibman Jul 23, 2024
768dd75
Merge branch 'master' into atsign
oleibman Jul 31, 2024
f3ae0bd
Merge branch 'master' into atsign
oleibman Aug 2, 2024
e5e6bde
Update Changelog and Docs Prior to Merge Next Week
oleibman Aug 2, 2024
823cb2d
Merge branch 'master' into atsign
oleibman Aug 10, 2024
fdbf333
Update CHANGELOG.md
oleibman Aug 10, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,32 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com)
and this project adheres to [Semantic Versioning](https://semver.org).

## TBD - 3.0.0

### Dynamic Arrays

- Support for Excel dynamic arrays is added. It is an opt-in feature, so our hope is that there will be no BC breaks, but it is a very large change. Full support is added for Xlsx. It is emulated as Ctrl-Shift-Enter arrays for Ods read and write and Excel2003 and Gnumeric read. Html/Pdf and Csv writers will populate cells on output if they are the result of array formulas. No support is added for Xls or Slk.

### Added

- Excel Dynamic Arrays. [Issue #3901](https://github.com/PHPOffice/PhpSpreadsheet/issues/3901) [Issue #3659](https://github.com/PHPOffice/PhpSpreadsheet/issues/3659) [Issue #1834](https://github.com/PHPOffice/PhpSpreadsheet/issues/1834) [PR #3962](https://github.com/PHPOffice/PhpSpreadsheet/pull/3962)

### Changed

- Nothing yet.

### Deprecated

- Nothing yet.

### Moved

- Nothing yet.

### Fixed

- Nothing yet.

## 2024-08-07 - 2.2.2

### Added
Expand Down
24 changes: 17 additions & 7 deletions docs/references/features-cross-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -365,15 +365,15 @@
<td style="text-align: center; color: red;">✖</td>
</tr>
<tr>
<td style="padding-left: 1em;">Array</td>
<td style="text-align: center; color: red;">✖</td>
<td style="text-align: center; color: red;">✖</td>
<td style="text-align: center; color: red;">✖</td>
<td style="text-align: center; color: red;">✖</td>
<td style="text-align: center; color: red;">✖</td>
<td style="text-align: center; color: red;">✖</td>
<td style="padding-left: 1em;">Array Formula</td>
<td style="text-align: center; color: red;">✖</td>
<td style="text-align: center; color: green;">✔</td>
<td style="text-align: center; color: green;">✔</td>
<td style="text-align: center; color: green;">✔</td>
<td style="text-align: center; color: green;">✔</td>
<td style="text-align: center;">N/A</td>
<td style="text-align: center; color: red;">✖</td>
<td style="text-align: center;">N/A</td>
</tr>
<tr>
<td style="padding-left: 1em;">Rich Text</td>
Expand Down Expand Up @@ -1005,6 +1005,7 @@
5. <span id="footnote5">Xlsx macros can be read and written; their values can be retrieved and changed, but only in a binary form which is unlikely to be useful</span>
6. <span id="footnote6">There is very limited support for reading styles from an Ods spreadsheet. Writing styles has better support, although Number Format is incomplete.</span>
7. <span id="footnote7">In most cases, Html reader processes only inline styles; styles provided by Css classes may be ignored.</span>
8. <span id="footnote8">Code must [opt in](../topics/recipes.md#array-formulas) to array output.</span>

## Writers

Expand Down Expand Up @@ -1175,6 +1176,15 @@
<td style="text-align: center; color: red;">✖</td>
<td style="text-align: center; color: red;">✖</td>
</tr>
<tr>
<td style="padding-left: 0.5em;"><strong>Array Formula<a href="#footnote8"><sup>8</sup></a></strong></td>
<td style="text-align: center; color: red;">✖</td>
<td style="text-align: center; color: green;">✔</td>
<td style="text-align: center; color: green;">✔</td>
<td style="text-align: center; color: green;">✔</td>
<td style="text-align: center; color: green;">✔</td>
<td style="text-align: center; color: green;">✔</td>
</tr>
<tr>
<td style="padding-left: 0.5em;"><strong>Rows and Column Properties</strong></td>
<td></td>
Expand Down
11 changes: 8 additions & 3 deletions docs/references/function-list-by-category.md
Original file line number Diff line number Diff line change
Expand Up @@ -529,7 +529,7 @@ CHAR | \PhpOffice\PhpSpreadsheet\Calculation\TextData\Charac
CLEAN | \PhpOffice\PhpSpreadsheet\Calculation\TextData\Trim::nonPrintable
CODE | \PhpOffice\PhpSpreadsheet\Calculation\TextData\CharacterConvert::code
CONCAT | \PhpOffice\PhpSpreadsheet\Calculation\TextData\Concatenate::CONCATENATE
CONCATENATE | \PhpOffice\PhpSpreadsheet\Calculation\TextData\Concatenate::CONCATENATE
CONCATENATE | \PhpOffice\PhpSpreadsheet\Calculation\TextData\Concatenate::actualCONCATENATE
DBCS | **Not yet Implemented**
DOLLAR | \PhpOffice\PhpSpreadsheet\Calculation\TextData\Format::DOLLAR
EXACT | \PhpOffice\PhpSpreadsheet\Calculation\TextData\Text::exact
Expand Down Expand Up @@ -586,5 +586,10 @@ WEBSERVICE | \PhpOffice\PhpSpreadsheet\Calculation\Web\Service::we

Excel Function | PhpSpreadsheet Function
-------------------------|--------------------------------------
ANCHORARRAY | **Not yet Implemented**
SINGLE | **Not yet Implemented**

## CATEGORY_MICROSOFT_INTERNAL

Excel Function | PhpSpreadsheet Function
-------------------------|--------------------------------------
ANCHORARRAY | \PhpOffice\PhpSpreadsheet\Calculation\Internal\ExcelArrayPseudoFunctions::anchorArray
SINGLE | \PhpOffice\PhpSpreadsheet\Calculation\Internal\ExcelArrayPseudoFunctions::single
6 changes: 3 additions & 3 deletions docs/references/function-list-by-name.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ ADDRESS | CATEGORY_LOOKUP_AND_REFERENCE | \PhpOffice\PhpSpread
AGGREGATE | CATEGORY_MATH_AND_TRIG | **Not yet Implemented**
AMORDEGRC | CATEGORY_FINANCIAL | \PhpOffice\PhpSpreadsheet\Calculation\Financial\Amortization::AMORDEGRC
AMORLINC | CATEGORY_FINANCIAL | \PhpOffice\PhpSpreadsheet\Calculation\Financial\Amortization::AMORLINC
ANCHORARRAY | CATEGORY_UNCATEGORISED | **Not yet Implemented**
ANCHORARRAY | CATEGORY_MICROSOFT_INTERNAL | \PhpOffice\PhpSpreadsheet\Calculation\Internal\ExcelArrayPseudoFunctions::anchorArray
AND | CATEGORY_LOGICAL | \PhpOffice\PhpSpreadsheet\Calculation\Logical\Operations::logicalAnd
ARABIC | CATEGORY_MATH_AND_TRIG | \PhpOffice\PhpSpreadsheet\Calculation\MathTrig\Arabic::evaluate
AREAS | CATEGORY_LOOKUP_AND_REFERENCE | **Not yet Implemented**
Expand Down Expand Up @@ -89,7 +89,7 @@ COMBIN | CATEGORY_MATH_AND_TRIG | \PhpOffice\PhpSpread
COMBINA | CATEGORY_MATH_AND_TRIG | \PhpOffice\PhpSpreadsheet\Calculation\MathTrig\Combinations::withRepetition
COMPLEX | CATEGORY_ENGINEERING | \PhpOffice\PhpSpreadsheet\Calculation\Engineering\Complex::COMPLEX
CONCAT | CATEGORY_TEXT_AND_DATA | \PhpOffice\PhpSpreadsheet\Calculation\TextData\Concatenate::CONCATENATE
CONCATENATE | CATEGORY_TEXT_AND_DATA | \PhpOffice\PhpSpreadsheet\Calculation\TextData\Concatenate::CONCATENATE
CONCATENATE | CATEGORY_TEXT_AND_DATA | \PhpOffice\PhpSpreadsheet\Calculation\TextData\Concatenate::actualCONCATENATE
CONFIDENCE | CATEGORY_STATISTICAL | \PhpOffice\PhpSpreadsheet\Calculation\Statistical\Confidence::CONFIDENCE
CONFIDENCE.NORM | CATEGORY_STATISTICAL | \PhpOffice\PhpSpreadsheet\Calculation\Statistical\Confidence::CONFIDENCE
CONFIDENCE.T | CATEGORY_STATISTICAL | **Not yet Implemented**
Expand Down Expand Up @@ -510,7 +510,7 @@ SHEET | CATEGORY_INFORMATION | **Not yet Implemente
SHEETS | CATEGORY_INFORMATION | **Not yet Implemented**
SIGN | CATEGORY_MATH_AND_TRIG | \PhpOffice\PhpSpreadsheet\Calculation\MathTrig\Sign::evaluate
SIN | CATEGORY_MATH_AND_TRIG | \PhpOffice\PhpSpreadsheet\Calculation\MathTrig\Trig\Sine::sin
SINGLE | CATEGORY_UNCATEGORISED | **Not yet Implemented**
SINGLE | CATEGORY_MICROSOFT_INTERNAL | \PhpOffice\PhpSpreadsheet\Calculation\Internal\ExcelArrayPseudoFunctions::single
SINH | CATEGORY_MATH_AND_TRIG | \PhpOffice\PhpSpreadsheet\Calculation\MathTrig\Trig\Sine::sinh
SKEW | CATEGORY_STATISTICAL | \PhpOffice\PhpSpreadsheet\Calculation\Statistical\Deviations::skew
SKEW.P | CATEGORY_STATISTICAL | **Not yet Implemented**
Expand Down
22 changes: 20 additions & 2 deletions docs/topics/calculation-engine.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ formula calculation capabilities. A cell can be of a value type
which can be evaluated). For example, the formula `=SUM(A1:A10)`
evaluates to the sum of values in A1, A2, ..., A10.

Calling `getValue()` on a cell that contains a formula will return the formula itself.

To calculate a formula, you can call the cell containing the formula’s
method `getCalculatedValue()`, for example:

Expand All @@ -22,7 +24,18 @@ with PhpSpreadsheet, it evaluates to the value "64":

![09-command-line-calculation.png](./images/09-command-line-calculation.png)

When writing a formula to a cell, formulae should always be set as they would appear in an English version of Microsoft Office Excel, and PhpSpreadsheet handles all formulae internally in this format. This means that the following rules hold:
Calling `getCalculatedValue()` on a cell that doesn't contain a formula will simply return the value of that cell; but if the cell does contain a formula, then PhpSpreadsheet will evaluate that formula to calculate the result.

There are a few useful mehods to help identify whether a cell contains a formula or a simple value; and if a formula, to provide further information about it:

```php
$spreadsheet->getActiveSheet()->getCell('E11')->isFormula();
```
will return a boolean true/false, telling you whether that cell contains a formula or not, so you can determine if a call to `getCalculatedVaue()` will need to perform an evaluation.

For more details on working with array formulas, see the [the recipes documentationn](./recipes.md/#array-formulas).

When writing a formula to a cell, formulas should always be set as they would appear in an English version of Microsoft Office Excel, and PhpSpreadsheet handles all formulas internally in this format. This means that the following rules hold:

- Decimal separator is `.` (period)
- Function argument separator is `,` (comma)
Expand Down Expand Up @@ -91,6 +104,11 @@ formula calculation is subject to PHP's language characteristics.
Not all functions are supported, for a comprehensive list, read the
[function list by name](../references/function-list-by-name.md).

#### Array arguments for Function Calls in Formulas

While most of the Excel function implementations now support array arguments, there are a few that should accept arrays as arguments but don't do so.
In these cases, the result may be a single value rather than an array; or it may be a `#VALUE!` error.

#### Operator precedence

In Excel `+` wins over `&`, just like `*` wins over `+` in ordinary
Expand Down Expand Up @@ -161,7 +179,7 @@ number of seconds from the PHP/Unix base date. The PHP/Unix base date
(0) is 00:00 UST on 1st January 1970. This value can be positive or
negative: so a value of -3600 would be 23:00 hrs on 31st December 1969;
while a value of +3600 would be 01:00 hrs on 1st January 1970. This
gives PHP a date range of between 14th December 1901 and 19th January
gives 32-bit PHP a date range of between 14th December 1901 and 19th January
2038.

#### PHP `DateTime` Objects
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
88 changes: 87 additions & 1 deletion docs/topics/reading-files.md
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,87 @@ Once you have created a reader object for the workbook that you want to
load, you have the opportunity to set additional options before
executing the `load()` method.

All of these options can be set by calling the appropriate methods against the Reader (as described below), but some options (those with only two possible values) can also be set through flags, either by calling the Reader's `setFlags()` method, or passing the flags as an argument in the call to `load()`.
Those options that can be set through flags are:

Option | Flag | Default
-------------------|-------------------------------------|------------------------
Empty Cells | IReader::IGNORE_EMPTY_CELLS | Load empty cells
Rows with no Cells | IReader::IGNORE_ROWS_WITH_NO_CELLS | Load rows with no cells
Data Only | IReader::READ_DATA_ONLY | Read data, structure and style
Charts | IReader::LOAD_WITH_CHARTS | Don't read charts

Several flags can be combined in a single call:
```php
$inputFileType = 'Xlsx';
$inputFileName = './sampleData/example1.xlsx';

/** Create a new Reader of the type defined in $inputFileType **/
$reader = \PhpOffice\PhpSpreadsheet\IOFactory::createReader($inputFileType);
/** Set additional flags before the call to load() */
$reader->setFlags(IReader::IGNORE_EMPTY_CELLS | IReader::LOAD_WITH_CHARTS);
$reader->load($inputFileName);
```
or
```php
$inputFileType = 'Xlsx';
$inputFileName = './sampleData/example1.xlsx';

/** Create a new Reader of the type defined in $inputFileType **/
$reader = \PhpOffice\PhpSpreadsheet\IOFactory::createReader($inputFileType);
/** Set additional flags in the call to load() */
$reader->load($inputFileName, IReader::IGNORE_EMPTY_CELLS | IReader::LOAD_WITH_CHARTS);
```

### Ignoring Empty Cells

Many Excel files have empty rows or columns at the end of a worksheet, which can't easily be seen when looking at the file in Excel (Try using Ctrl-End to see the last cell in a worksheet).
By default, PhpSpreadsheet will load these cells, because they are valid Excel values; but you may find that an apparently small spreadsheet requires a lot of memory for all those empty cells.
If you are running into memory issues with seemingly small files, you can tell PhpSpreadsheet not to load those empty cells using the `setReadEmptyCells()` method.

```php
$inputFileType = 'Xls';
$inputFileName = './sampleData/example1.xls';

/** Create a new Reader of the type defined in $inputFileType **/
$reader = \PhpOffice\PhpSpreadsheet\IOFactory::createReader($inputFileType);
/** Advise the Reader that we only want to load cell's that contain actual content **/
$reader->setReadEmptyCells(false);
/** Load $inputFileName to a Spreadsheet Object **/
$spreadsheet = $reader->load($inputFileName);
```

Note that cells containing formulae will still be loaded, even if that formula evaluates to a NULL or an empty string.
Similarly, Conditional Styling might also hide the value of a cell; but cells that contain Conditional Styling or Data Validation will always be loaded regardless of their value.

This option is available for the following formats:

Reader | Y/N |Reader | Y/N |Reader | Y/N |
----------|:---:|--------|:---:|--------------|:---:|
Xlsx | YES | Xls | YES | Xml | NO |
Ods | NO | SYLK | NO | Gnumeric | NO |
CSV | NO | HTML | NO

This option is also available through flags.

### Ignoring Rows With No Cells

Similar to the previous item, you can choose to ignore rows which contain no cells.
This can also help with memory issues.
```php
$inputFileType = 'Xlsx';
$inputFileName = './sampleData/example1.xlsx';

/** Create a new Reader of the type defined in $inputFileType **/
$reader = \PhpOffice\PhpSpreadsheet\IOFactory::createReader($inputFileType);
/** Advise the Reader that we do not want rows with no cells **/
$reader->setIgnoreRowsWithNoCells(true);
/** Load $inputFileName to a Spreadsheet Object **/
$spreadsheet = $reader->load($inputFileName);
```

This option is available only for Xlsx. It is also available through flags.

### Reading Only Data from a Spreadsheet File

If you're only interested in the cell values in a workbook, but don't
Expand Down Expand Up @@ -210,6 +291,8 @@ Xlsx | YES | Xls | YES | Xml | YES |
Ods | YES | SYLK | NO | Gnumeric | YES |
CSV | NO | HTML | NO

This option is also available through flags.

### Reading Only Named WorkSheets from a File

If your workbook contains a number of worksheets, but you are only
Expand Down Expand Up @@ -642,7 +725,7 @@ Xlsx | NO | Xls | NO | Xml | NO |
Ods | NO | SYLK | NO | Gnumeric | NO |
CSV | YES | HTML | NO

### A Brief Word about the Advanced Value Binder
## A Brief Word about the Advanced Value Binder

When loading data from a file that contains no formatting information,
such as a CSV file, then data is read either as strings or numbers
Expand Down Expand Up @@ -694,6 +777,9 @@ Xlsx | NO | Xls | NO | Xml | NO
Ods | NO | SYLK | NO | Gnumeric | NO
CSV | YES | HTML | YES

Note that you can also use the Binder to determine how PhpSpreadsheet identified datatypes for values when you set a cell value without explicitly setting a datatype.
Value Binders can also be used to set formatting for a cell appropriate to the value.

## Error Handling

Of course, you should always apply some error handling to your scripts
Expand Down
Loading
Loading