Merge branch 'master' into Table-Reader-for-Xlsx
This commit is contained in:
commit
e1ab240419
19
CHANGELOG.md
19
CHANGELOG.md
|
|
@ -9,13 +9,21 @@ and this project adheres to [Semantic Versioning](https://semver.org).
|
|||
|
||||
### Added
|
||||
|
||||
- Add point size option for scatter charts
|
||||
- Add point size option for scatter charts [Issue #2298](https://github.com/PHPOffice/PhpSpreadsheet/issues/2298) [PR #2801](https://github.com/PHPOffice/PhpSpreadsheet/pull/2801)
|
||||
- Basic support for Xlsx reading/writing Chart Sheets [PR #2830](https://github.com/PHPOffice/PhpSpreadsheet/pull/2830)
|
||||
|
||||
Note that a ChartSheet is still only written as a normal Worksheet containing a single chart, not as an actual ChartSheet.
|
||||
|
||||
- Added Worksheet visibility in Ods Reader [PR #2851](https://github.com/PHPOffice/PhpSpreadsheet/pull/2851) and Gnumeric Reader [PR #2853](https://github.com/PHPOffice/PhpSpreadsheet/pull/2853)
|
||||
- Added Worksheet visibility in Ods Writer [PR #2850](https://github.com/PHPOffice/PhpSpreadsheet/pull/2850)
|
||||
- Allow Csv Reader to treat string as contents of file [Issue #1285](https://github.com/PHPOffice/PhpSpreadsheet/issues/1285) [PR #2792](https://github.com/PHPOffice/PhpSpreadsheet/pull/2792)
|
||||
- Allow Csv Reader to store null string rather than leave cell empty [Issue #2840](https://github.com/PHPOffice/PhpSpreadsheet/issues/2840) [PR #2842](https://github.com/PHPOffice/PhpSpreadsheet/pull/2842)
|
||||
|
||||
### Changed
|
||||
|
||||
- Memory and speed improvements, particularly for the Cell Collection, and the Writers.
|
||||
|
||||
See [the Discussion](https://github.com/PHPOffice/PhpSpreadsheet/discussions/2821) for details of performance
|
||||
See [the Discussion section on github](https://github.com/PHPOffice/PhpSpreadsheet/discussions/2821) for details of performance across versions
|
||||
|
||||
### Deprecated
|
||||
|
||||
|
|
@ -28,7 +36,12 @@ and this project adheres to [Semantic Versioning](https://semver.org).
|
|||
### Fixed
|
||||
|
||||
- Xls Reader resolving absolute named ranges to relative ranges [Issue #2826](https://github.com/PHPOffice/PhpSpreadsheet/issues/2826) [PR #2827](https://github.com/PHPOffice/PhpSpreadsheet/pull/2827)
|
||||
|
||||
- Null value handling in the Excel Math/Trig PRODUCT() function [Issue #2833](https://github.com/PHPOffice/PhpSpreadsheet/issues/2833) [PR #2834](https://github.com/PHPOffice/PhpSpreadsheet/pull/2834)
|
||||
- Invalid Print Area defined in Xlsx corrupts internal storage of print area [Issue #2848](https://github.com/PHPOffice/PhpSpreadsheet/issues/2848) [PR #2849](https://github.com/PHPOffice/PhpSpreadsheet/pull/2849)
|
||||
- Time interval formatting [Issue #2768](https://github.com/PHPOffice/PhpSpreadsheet/issues/2768) [PR #2772](https://github.com/PHPOffice/PhpSpreadsheet/pull/2772)
|
||||
- Copy from Xls(x) to Html/Pdf loses drawings [PR #2788](https://github.com/PHPOffice/PhpSpreadsheet/pull/2788)
|
||||
- Html Reader converting cell containing 0 to null string [Issue #2810](https://github.com/PHPOffice/PhpSpreadsheet/issues/2810) [PR #2813](https://github.com/PHPOffice/PhpSpreadsheet/pull/2813)
|
||||
- Many fixes for Charts, especially, but not limited to, Scatter, Bubble, and Surface charts. [Issue #2762](https://github.com/PHPOffice/PhpSpreadsheet/issues/2762) [Issue #2299](https://github.com/PHPOffice/PhpSpreadsheet/issues/2299) [Issue #2700](https://github.com/PHPOffice/PhpSpreadsheet/issues/2700) [Issue #2817](https://github.com/PHPOffice/PhpSpreadsheet/issues/2817) [Issue #2763](https://github.com/PHPOffice/PhpSpreadsheet/issues/2763) [PR #2828](https://github.com/PHPOffice/PhpSpreadsheet/pull/2828) [PR #2841](https://github.com/PHPOffice/PhpSpreadsheet/pull/2841) [PR #2846](https://github.com/PHPOffice/PhpSpreadsheet/pull/2846) [PR #2852](https://github.com/PHPOffice/PhpSpreadsheet/pull/2852)
|
||||
|
||||
## 1.23.0 - 2022-04-24
|
||||
|
||||
|
|
|
|||
38
README.md
38
README.md
|
|
@ -11,6 +11,44 @@
|
|||
PhpSpreadsheet is a library written in pure PHP and offers a set of classes that
|
||||
allow you to read and write various spreadsheet file formats such as Excel and LibreOffice Calc.
|
||||
|
||||
## PHP version support
|
||||
|
||||
LTS: Support for PHP versions will only be maintained for a period of six months beyond the
|
||||
[end of life of that PHP version](https://www.php.net/eol.php).
|
||||
|
||||
Currently the required PHP minimum version is PHP __7.3__.
|
||||
|
||||
See the `composer.json` for other requirements.
|
||||
|
||||
## Installation
|
||||
|
||||
Use [composer](https://getcomposer.org) to install PhpSpreadsheet into your project:
|
||||
|
||||
```sh
|
||||
composer require phpoffice/phpspreadsheet
|
||||
```
|
||||
|
||||
If you are building your installation on a development machine that is on a different PHP version to the server where it will be deployed, or if your PHP CLI version is not the same as your run-time such as `php-fpm` or Apache's `mod_php`, then you might want to add the following to your `composer.json` before installing:
|
||||
```json lines
|
||||
{
|
||||
"require": {
|
||||
"phpoffice/phpspreadsheet": "^1.23"
|
||||
},
|
||||
"config": {
|
||||
"platform": {
|
||||
"php": "7.3"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
and then run
|
||||
```sh
|
||||
composer install
|
||||
```
|
||||
to ensure that the correct dependencies are retrieved to match your deployment environment.
|
||||
|
||||
See [CLI vs Application run-time](https://php.watch/articles/composer-platform-check) for more details.
|
||||
|
||||
## Documentation
|
||||
|
||||
Read more about it, including install instructions, in the [official documentation](https://phpspreadsheet.readthedocs.io). Or check out the [API documentation](https://phpoffice.github.io/PhpSpreadsheet).
|
||||
|
|
|
|||
|
|
@ -30,9 +30,14 @@ for details.
|
|||
|
||||
### PHP version support
|
||||
|
||||
Support for PHP versions will only be maintained for a period of six months beyond the
|
||||
LTS: Support for PHP versions will only be maintained for a period of six months beyond the
|
||||
[end of life of that PHP version](https://www.php.net/eol.php).
|
||||
|
||||
Currently the required PHP minimum version is PHP 7.3. The last PHP release was 7.3.33 on 6th December 2021, so PhpSpreadsheet will support PHP 7.3 until 6th June 2022.
|
||||
PHP 7.4 is officially [End of Life](https://www.php.net/supported-versions.php) on 28th November 2022, and PhpSpreadsheet will continue to support PHP 7.4 for six months after that date.
|
||||
|
||||
See the `composer.json` for other requirements.
|
||||
|
||||
## Installation
|
||||
|
||||
Use [composer](https://getcomposer.org) to install PhpSpreadsheet into your project:
|
||||
|
|
@ -47,6 +52,26 @@ Or also download the documentation and samples if you plan to use them:
|
|||
composer require phpoffice/phpspreadsheet --prefer-source
|
||||
```
|
||||
|
||||
If you are building your installation on a development machine that is on a different PHP version to the server where it will be deployed, or if your PHP CLI version is not the same as your run-time such as `php-fpm` or Apache's `mod_php`, then you might want to add the following to your `composer.json` before installing:
|
||||
```json lines
|
||||
{
|
||||
"require": {
|
||||
"phpoffice/phpspreadsheet": "^1.23"
|
||||
},
|
||||
"config": {
|
||||
"platform": {
|
||||
"php": "7.3"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
and then run
|
||||
```sh
|
||||
composer install
|
||||
```
|
||||
to ensure that the correct dependencies are retrieved to match your deployment environment.
|
||||
|
||||
See [CLI vs Application run-time](https://php.watch/articles/composer-platform-check) for more details.
|
||||
|
||||
## Hello World
|
||||
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@
|
|||
<th></th>
|
||||
<th>XLS</th>
|
||||
<th>XLSX</th>
|
||||
<th>Excel2003XML</th>
|
||||
<th>XML (Excel2003XML)</th>
|
||||
<th>Ods</th>
|
||||
<th>Gnumeric</th>
|
||||
<th>CSV</th>
|
||||
|
|
@ -732,12 +732,32 @@
|
|||
<td></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="padding-left: 1em;">Hidden Worksheets</td>
|
||||
<td style="text-align: center; color: green;">✔</td>
|
||||
<td style="text-align: center; color: green;">✔</td>
|
||||
<td></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></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="padding-left: 1em;">Coloured Tabs</td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td style="text-align: center;">N/A</td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
|
|
|
|||
|
|
@ -449,8 +449,7 @@ $spreadsheet = $reader->loadSpreadsheetFromString($data);
|
|||
#### Setting CSV options
|
||||
|
||||
Often, CSV files are not really "comma separated", or use semicolon (`;`)
|
||||
as a separator. You can instruct
|
||||
`\PhpOffice\PhpSpreadsheet\Reader\Csv` some options before reading a CSV
|
||||
as a separator. You can set some options before reading a CSV
|
||||
file.
|
||||
|
||||
The separator will be auto-detected, so in most cases it should not be necessary
|
||||
|
|
@ -506,6 +505,12 @@ $reader->setSheetIndex(0);
|
|||
$spreadsheet = $reader->load('sample.csv');
|
||||
```
|
||||
|
||||
The CSV reader will normally not load null strings into the spreadsheet.
|
||||
To load them:
|
||||
```php
|
||||
$reader->setPreserveNullString(true);
|
||||
```
|
||||
|
||||
Finally, you can set a callback to be invoked when the constructor is executed,
|
||||
either through `new Csv()` or `IOFactory::load`,
|
||||
and have that callback set the customizable attributes to whatever
|
||||
|
|
@ -584,8 +589,7 @@ $writer->save("05featuredemo.csv");
|
|||
#### Setting CSV options
|
||||
|
||||
Often, CSV files are not really "comma separated", or use semicolon (`;`)
|
||||
as a separator. You can instruct
|
||||
`\PhpOffice\PhpSpreadsheet\Writer\Csv` some options before writing a CSV
|
||||
as a separator. You can set some options before writing a CSV
|
||||
file:
|
||||
|
||||
```php
|
||||
|
|
|
|||
|
|
@ -125,11 +125,6 @@ parameters:
|
|||
count: 1
|
||||
path: src/PhpSpreadsheet/Calculation/Calculation.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#3 \\$formula of static method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Calculation\\:\\:translateSeparator\\(\\) expects string, string\\|null given\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Calculation/Calculation.php
|
||||
|
||||
-
|
||||
message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Calculation\\:\\:\\$cellStack has no type specified\\.$#"
|
||||
count: 1
|
||||
|
|
@ -750,11 +745,6 @@ parameters:
|
|||
count: 1
|
||||
path: src/PhpSpreadsheet/Calculation/LookupRef/Offset.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#1 \\$columnAddress of static method PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Coordinate\\:\\:columnIndexFromString\\(\\) expects string, string\\|null given\\.$#"
|
||||
count: 3
|
||||
path: src/PhpSpreadsheet/Calculation/LookupRef/RowColumnInformation.php
|
||||
|
||||
-
|
||||
message: "#^Binary operation \"/\" between array\\|float\\|int\\|string and array\\|float\\|int\\|string results in an error\\.$#"
|
||||
count: 2
|
||||
|
|
@ -1160,76 +1150,6 @@ parameters:
|
|||
count: 1
|
||||
path: src/PhpSpreadsheet/Chart/Chart.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Chart\\:\\:getBottomRightXOffset\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Chart/Chart.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Chart\\:\\:getBottomRightYOffset\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Chart/Chart.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Chart\\:\\:getTopLeftXOffset\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Chart/Chart.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Chart\\:\\:getTopLeftYOffset\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Chart/Chart.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Chart\\:\\:setBottomRightCell\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Chart/Chart.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Chart\\:\\:setBottomRightCell\\(\\) has parameter \\$cell with no type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Chart/Chart.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Chart\\:\\:setBottomRightXOffset\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Chart/Chart.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Chart\\:\\:setBottomRightXOffset\\(\\) has parameter \\$xOffset with no type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Chart/Chart.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Chart\\:\\:setBottomRightYOffset\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Chart/Chart.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Chart\\:\\:setBottomRightYOffset\\(\\) has parameter \\$yOffset with no type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Chart/Chart.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Chart\\:\\:setTopLeftXOffset\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Chart/Chart.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Chart\\:\\:setTopLeftXOffset\\(\\) has parameter \\$xOffset with no type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Chart/Chart.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Chart\\:\\:setTopLeftYOffset\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Chart/Chart.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Chart\\:\\:setTopLeftYOffset\\(\\) has parameter \\$yOffset with no type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Chart/Chart.php
|
||||
|
||||
-
|
||||
message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Chart\\:\\:\\$legend \\(PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Legend\\) does not accept PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Legend\\|null\\.$#"
|
||||
count: 1
|
||||
|
|
@ -1285,26 +1205,6 @@ parameters:
|
|||
count: 2
|
||||
path: src/PhpSpreadsheet/Chart/DataSeries.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\DataSeriesValues\\:\\:refresh\\(\\) has parameter \\$flatten with no type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Chart/DataSeriesValues.php
|
||||
|
||||
-
|
||||
message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\DataSeriesValues\\:\\:\\$dataSource \\(string\\) does not accept string\\|null\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Chart/DataSeriesValues.php
|
||||
|
||||
-
|
||||
message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\DataSeriesValues\\:\\:\\$dataTypeValues has no type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Chart/DataSeriesValues.php
|
||||
|
||||
-
|
||||
message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\DataSeriesValues\\:\\:\\$fillColor \\(array\\<string\\>\\|string\\) does not accept array\\<string\\>\\|string\\|null\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Chart/DataSeriesValues.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#1 \\$angle of method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\GridLines\\:\\:setShadowAngle\\(\\) expects int, int\\|null given\\.$#"
|
||||
count: 1
|
||||
|
|
@ -1800,11 +1700,6 @@ parameters:
|
|||
count: 1
|
||||
path: src/PhpSpreadsheet/Helper/Html.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#1 \\$text of method PhpOffice\\\\PhpSpreadsheet\\\\RichText\\\\ITextElement\\:\\:setText\\(\\) expects string, string\\|null given\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Helper/Html.php
|
||||
|
||||
-
|
||||
message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Helper\\\\Html\\:\\:\\$bold has no type specified\\.$#"
|
||||
count: 1
|
||||
|
|
@ -1905,11 +1800,6 @@ parameters:
|
|||
count: 1
|
||||
path: src/PhpSpreadsheet/Helper/Sample.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#3 \\$subject of function str_replace expects array\\|string, string\\|null given\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Helper/Sample.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\IOFactory\\:\\:createReader\\(\\) should return PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\IReader but returns object\\.$#"
|
||||
count: 1
|
||||
|
|
@ -2035,36 +1925,11 @@ parameters:
|
|||
count: 6
|
||||
path: src/PhpSpreadsheet/Reader/Ods/PageSettings.php
|
||||
|
||||
-
|
||||
message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Ods\\\\PageSettings\\:\\:\\$masterPrintStylesCrossReference has no type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Reader/Ods/PageSettings.php
|
||||
|
||||
-
|
||||
message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Ods\\\\PageSettings\\:\\:\\$masterStylesCrossReference has no type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Reader/Ods/PageSettings.php
|
||||
|
||||
-
|
||||
message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Ods\\\\PageSettings\\:\\:\\$officeNs has no type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Reader/Ods/PageSettings.php
|
||||
|
||||
-
|
||||
message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Ods\\\\PageSettings\\:\\:\\$pageLayoutStyles has no type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Reader/Ods/PageSettings.php
|
||||
|
||||
-
|
||||
message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Ods\\\\PageSettings\\:\\:\\$stylesFo has no type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Reader/Ods/PageSettings.php
|
||||
|
||||
-
|
||||
message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Ods\\\\PageSettings\\:\\:\\$stylesNs has no type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Reader/Ods/PageSettings.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Ods\\\\Properties\\:\\:load\\(\\) has parameter \\$namespacesMeta with no type specified\\.$#"
|
||||
count: 1
|
||||
|
|
@ -2396,7 +2261,7 @@ parameters:
|
|||
path: src/PhpSpreadsheet/Reader/Xlsx.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\:\\:boolean\\(\\) has no return type specified\\.$#"
|
||||
message: "#^Comparison operation \"\\>\" between SimpleXMLElement\\|null and 0 results in an error\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Reader/Xlsx.php
|
||||
|
||||
|
|
@ -2470,11 +2335,6 @@ parameters:
|
|||
count: 1
|
||||
path: src/PhpSpreadsheet/Reader/Xlsx.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\:\\:dirAdd\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Reader/Xlsx.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\:\\:dirAdd\\(\\) has parameter \\$add with no type specified\\.$#"
|
||||
count: 1
|
||||
|
|
@ -2535,21 +2395,11 @@ parameters:
|
|||
count: 1
|
||||
path: src/PhpSpreadsheet/Reader/Xlsx.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\:\\:stripWhiteSpaceFromStyleString\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Reader/Xlsx.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\:\\:stripWhiteSpaceFromStyleString\\(\\) has parameter \\$string with no type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Reader/Xlsx.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\:\\:toCSSArray\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Reader/Xlsx.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\:\\:toCSSArray\\(\\) has parameter \\$style with no type specified\\.$#"
|
||||
count: 1
|
||||
|
|
@ -2625,206 +2475,6 @@ parameters:
|
|||
count: 1
|
||||
path: src/PhpSpreadsheet/Reader/Xlsx/BaseParserClass.php
|
||||
|
||||
-
|
||||
message: "#^Cannot call method getFont\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\RichText\\\\Run\\|null\\.$#"
|
||||
count: 12
|
||||
path: src/PhpSpreadsheet/Reader/Xlsx/Chart.php
|
||||
|
||||
-
|
||||
message: "#^Cannot call method setBold\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Font\\|null\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Reader/Xlsx/Chart.php
|
||||
|
||||
-
|
||||
message: "#^Cannot call method setColor\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Font\\|null\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Reader/Xlsx/Chart.php
|
||||
|
||||
-
|
||||
message: "#^Cannot call method setItalic\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Font\\|null\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Reader/Xlsx/Chart.php
|
||||
|
||||
-
|
||||
message: "#^Cannot call method setName\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Font\\|null\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Reader/Xlsx/Chart.php
|
||||
|
||||
-
|
||||
message: "#^Cannot call method setSize\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Font\\|null\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Reader/Xlsx/Chart.php
|
||||
|
||||
-
|
||||
message: "#^Cannot call method setStrikethrough\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Font\\|null\\.$#"
|
||||
count: 2
|
||||
path: src/PhpSpreadsheet/Reader/Xlsx/Chart.php
|
||||
|
||||
-
|
||||
message: "#^Cannot call method setSubscript\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Font\\|null\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Reader/Xlsx/Chart.php
|
||||
|
||||
-
|
||||
message: "#^Cannot call method setSuperscript\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Font\\|null\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Reader/Xlsx/Chart.php
|
||||
|
||||
-
|
||||
message: "#^Cannot call method setUnderline\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Font\\|null\\.$#"
|
||||
count: 3
|
||||
path: src/PhpSpreadsheet/Reader/Xlsx/Chart.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\Chart\\:\\:chartDataSeries\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Reader/Xlsx/Chart.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\Chart\\:\\:chartDataSeries\\(\\) has parameter \\$chartDetail with no type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Reader/Xlsx/Chart.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\Chart\\:\\:chartDataSeries\\(\\) has parameter \\$namespacesChartMeta with no type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Reader/Xlsx/Chart.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\Chart\\:\\:chartDataSeries\\(\\) has parameter \\$plotType with no type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Reader/Xlsx/Chart.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\Chart\\:\\:chartDataSeriesValueSet\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Reader/Xlsx/Chart.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\Chart\\:\\:chartDataSeriesValueSet\\(\\) has parameter \\$marker with no type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Reader/Xlsx/Chart.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\Chart\\:\\:chartDataSeriesValueSet\\(\\) has parameter \\$namespacesChartMeta with no type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Reader/Xlsx/Chart.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\Chart\\:\\:chartDataSeriesValueSet\\(\\) has parameter \\$seriesDetail with no type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Reader/Xlsx/Chart.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\Chart\\:\\:chartDataSeriesValues\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Reader/Xlsx/Chart.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\Chart\\:\\:chartDataSeriesValues\\(\\) has parameter \\$dataType with no type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Reader/Xlsx/Chart.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\Chart\\:\\:chartDataSeriesValues\\(\\) has parameter \\$seriesValueSet with no type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Reader/Xlsx/Chart.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\Chart\\:\\:chartDataSeriesValuesMultiLevel\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Reader/Xlsx/Chart.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\Chart\\:\\:chartDataSeriesValuesMultiLevel\\(\\) has parameter \\$dataType with no type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Reader/Xlsx/Chart.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\Chart\\:\\:chartDataSeriesValuesMultiLevel\\(\\) has parameter \\$seriesValueSet with no type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Reader/Xlsx/Chart.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\Chart\\:\\:chartLayoutDetails\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Reader/Xlsx/Chart.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\Chart\\:\\:chartLayoutDetails\\(\\) has parameter \\$chartDetail with no type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Reader/Xlsx/Chart.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\Chart\\:\\:chartLayoutDetails\\(\\) has parameter \\$namespacesChartMeta with no type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Reader/Xlsx/Chart.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\Chart\\:\\:chartTitle\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Reader/Xlsx/Chart.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\Chart\\:\\:parseRichText\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Reader/Xlsx/Chart.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\Chart\\:\\:readChartAttributes\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Reader/Xlsx/Chart.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\Chart\\:\\:readChartAttributes\\(\\) has parameter \\$chartDetail with no type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Reader/Xlsx/Chart.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\Chart\\:\\:readColor\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Reader/Xlsx/Chart.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\Chart\\:\\:readColor\\(\\) has parameter \\$background with no type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Reader/Xlsx/Chart.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\Chart\\:\\:readColor\\(\\) has parameter \\$color with no type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Reader/Xlsx/Chart.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#1 \\$position of class PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Legend constructor expects string, bool\\|float\\|int\\|string\\|null given\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Reader/Xlsx/Chart.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#3 \\$overlay of class PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Legend constructor expects bool, bool\\|float\\|int\\|string\\|null given\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Reader/Xlsx/Chart.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#3 \\$plotOrder of class PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\DataSeries constructor expects array\\<int\\>, array\\<int\\|string, bool\\|float\\|int\\|string\\|null\\> given\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Reader/Xlsx/Chart.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#4 \\$pointCount of class PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\DataSeriesValues constructor expects int, null given\\.$#"
|
||||
count: 4
|
||||
path: src/PhpSpreadsheet/Reader/Xlsx/Chart.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#6 \\$displayBlanksAs of class PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Chart constructor expects string, bool\\|float\\|int\\|string\\|null given\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Reader/Xlsx/Chart.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#7 \\$plotDirection of class PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\DataSeries constructor expects string\\|null, bool\\|float\\|int\\|string\\|null given\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Reader/Xlsx/Chart.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\ColumnAndRowAttributes\\:\\:isFilteredColumn\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
|
|
@ -3035,11 +2685,6 @@ parameters:
|
|||
count: 1
|
||||
path: src/PhpSpreadsheet/ReferenceHelper.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#3 \\$subject of function str_replace expects array\\|string, string\\|null given\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/ReferenceHelper.php
|
||||
|
||||
-
|
||||
message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\RichText\\\\Run\\:\\:\\$font \\(PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Font\\) does not accept PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Font\\|null\\.$#"
|
||||
count: 1
|
||||
|
|
@ -4035,26 +3680,11 @@ parameters:
|
|||
count: 1
|
||||
path: src/PhpSpreadsheet/Style/NumberFormat/Formatter.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#2 \\$subject of function preg_split expects string, string\\|null given\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Style/NumberFormat/Formatter.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#3 \\$subject of function preg_replace expects array\\|string, string\\|null given\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Style/NumberFormat/Formatter.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\NumberFormat\\\\PercentageFormatter\\:\\:format\\(\\) has parameter \\$value with no type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Style/NumberFormat/PercentageFormatter.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#1 \\$format of function sprintf expects string, string\\|null given\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Style/NumberFormat/PercentageFormatter.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\CellIterator\\:\\:adjustForExistingOnlyRange\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
|
|
@ -4490,11 +4120,6 @@ parameters:
|
|||
count: 1
|
||||
path: src/PhpSpreadsheet/Writer/Html.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#1 \\$string of function htmlspecialchars expects string, string\\|null given\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Writer/Html.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#1 \\$vAlign of method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Html\\:\\:mapVAlign\\(\\) expects string, string\\|null given\\.$#"
|
||||
count: 1
|
||||
|
|
@ -4690,16 +4315,6 @@ parameters:
|
|||
count: 7
|
||||
path: src/PhpSpreadsheet/Writer/Xls/Parser.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#3 \\$subject of function preg_replace expects array\\|string, string\\|null given\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Writer/Xls/Parser.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#3 \\$subject of function str_replace expects array\\|string, string\\|null given\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Writer/Xls/Parser.php
|
||||
|
||||
-
|
||||
message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xls\\\\Parser\\:\\:\\$spreadsheet has no type specified\\.$#"
|
||||
count: 1
|
||||
|
|
@ -4800,21 +4415,6 @@ parameters:
|
|||
count: 1
|
||||
path: src/PhpSpreadsheet/Writer/Xls/Worksheet.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#2 \\$subject of function preg_match expects string, string\\|null given\\.$#"
|
||||
count: 2
|
||||
path: src/PhpSpreadsheet/Writer/Xls/Worksheet.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#2 \\$subject of function preg_match_all expects string, string\\|null given\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Writer/Xls/Worksheet.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#3 \\$subject of function preg_replace expects array\\|string, string\\|null given\\.$#"
|
||||
count: 2
|
||||
path: src/PhpSpreadsheet/Writer/Xls/Worksheet.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#4 \\$isError of method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xls\\\\Worksheet\\:\\:writeBoolErr\\(\\) expects bool, int given\\.$#"
|
||||
count: 3
|
||||
|
|
@ -4947,7 +4547,7 @@ parameters:
|
|||
|
||||
-
|
||||
message: "#^Parameter \\#2 \\$value of method XMLWriter\\:\\:writeAttribute\\(\\) expects string, int given\\.$#"
|
||||
count: 44
|
||||
count: 42
|
||||
path: src/PhpSpreadsheet/Writer/Xlsx/Chart.php
|
||||
|
||||
-
|
||||
|
|
@ -4955,26 +4555,6 @@ parameters:
|
|||
count: 2
|
||||
path: src/PhpSpreadsheet/Writer/Xlsx/Chart.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#3 \\$id1 of method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xlsx\\\\Chart\\:\\:writeCategoryAxis\\(\\) expects string, int\\|string given\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Writer/Xlsx/Chart.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#4 \\$id1 of method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xlsx\\\\Chart\\:\\:writeValueAxis\\(\\) expects string, int\\|string given\\.$#"
|
||||
count: 2
|
||||
path: src/PhpSpreadsheet/Writer/Xlsx/Chart.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#4 \\$id2 of method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xlsx\\\\Chart\\:\\:writeCategoryAxis\\(\\) expects string, int\\|string given\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Writer/Xlsx/Chart.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#5 \\$id2 of method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xlsx\\\\Chart\\:\\:writeValueAxis\\(\\) expects string, int\\|string given\\.$#"
|
||||
count: 2
|
||||
path: src/PhpSpreadsheet/Writer/Xlsx/Chart.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#6 \\$yAxis of method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xlsx\\\\Chart\\:\\:writeCategoryAxis\\(\\) expects PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Axis, PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Axis\\|null given\\.$#"
|
||||
count: 1
|
||||
|
|
@ -5062,7 +4642,7 @@ parameters:
|
|||
|
||||
-
|
||||
message: "#^Cannot call method getBold\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Font\\|null\\.$#"
|
||||
count: 2
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Writer/Xlsx/StringTable.php
|
||||
|
||||
-
|
||||
|
|
@ -5072,12 +4652,12 @@ parameters:
|
|||
|
||||
-
|
||||
message: "#^Cannot call method getItalic\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Font\\|null\\.$#"
|
||||
count: 2
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Writer/Xlsx/StringTable.php
|
||||
|
||||
-
|
||||
message: "#^Cannot call method getName\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Font\\|null\\.$#"
|
||||
count: 2
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Writer/Xlsx/StringTable.php
|
||||
|
||||
-
|
||||
|
|
@ -5087,7 +4667,7 @@ parameters:
|
|||
|
||||
-
|
||||
message: "#^Cannot call method getStrikethrough\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Font\\|null\\.$#"
|
||||
count: 2
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Writer/Xlsx/StringTable.php
|
||||
|
||||
-
|
||||
|
|
@ -5102,7 +4682,7 @@ parameters:
|
|||
|
||||
-
|
||||
message: "#^Cannot call method getUnderline\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Font\\|null\\.$#"
|
||||
count: 2
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Writer/Xlsx/StringTable.php
|
||||
|
||||
-
|
||||
|
|
@ -5137,7 +4717,7 @@ parameters:
|
|||
|
||||
-
|
||||
message: "#^Parameter \\#2 \\$value of method XMLWriter\\:\\:writeAttribute\\(\\) expects string, string\\|null given\\.$#"
|
||||
count: 5
|
||||
count: 4
|
||||
path: src/PhpSpreadsheet/Writer/Xlsx/StringTable.php
|
||||
|
||||
-
|
||||
|
|
@ -5285,8 +4865,3 @@ parameters:
|
|||
count: 2
|
||||
path: src/PhpSpreadsheet/Writer/Xlsx/Worksheet.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xlsx\\\\Xlfn\\:\\:addXlfn\\(\\) should return string but returns string\\|null\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Writer/Xlsx/Xlfn.php
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,124 @@
|
|||
<?php
|
||||
|
||||
use PhpOffice\PhpSpreadsheet\Chart\Chart;
|
||||
use PhpOffice\PhpSpreadsheet\Chart\DataSeries;
|
||||
use PhpOffice\PhpSpreadsheet\Chart\DataSeriesValues;
|
||||
use PhpOffice\PhpSpreadsheet\Chart\Legend as ChartLegend;
|
||||
use PhpOffice\PhpSpreadsheet\Chart\PlotArea;
|
||||
use PhpOffice\PhpSpreadsheet\Chart\Title;
|
||||
use PhpOffice\PhpSpreadsheet\IOFactory;
|
||||
use PhpOffice\PhpSpreadsheet\Spreadsheet;
|
||||
|
||||
require __DIR__ . '/../Header.php';
|
||||
|
||||
$spreadsheet = new Spreadsheet();
|
||||
$worksheet = $spreadsheet->getActiveSheet();
|
||||
$worksheet->fromArray(
|
||||
[
|
||||
['Number of Products', 'Sales in USD', 'Market share'],
|
||||
[14, 12200, 15],
|
||||
[20, 60000, 33],
|
||||
[18, 24400, 10],
|
||||
[22, 32000, 42],
|
||||
[],
|
||||
[12, 8200, 18],
|
||||
[15, 50000, 30],
|
||||
[19, 22400, 15],
|
||||
[25, 25000, 50],
|
||||
]
|
||||
);
|
||||
|
||||
// Set the Labels for each data series we want to plot
|
||||
// Datatype
|
||||
// Cell reference for data
|
||||
// Format Code
|
||||
// Number of datapoints in series
|
||||
// Data values
|
||||
// Data Marker
|
||||
|
||||
$dataSeriesLabels = [
|
||||
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, null, null, 1, ['2013']), // 2013
|
||||
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, null, null, 1, ['2014']), // 2014
|
||||
];
|
||||
|
||||
// Set the X-Axis values
|
||||
// Datatype
|
||||
// Cell reference for data
|
||||
// Format Code
|
||||
// Number of datapoints in series
|
||||
// Data values
|
||||
// Data Marker
|
||||
$dataSeriesCategories = [
|
||||
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, 'Worksheet!$A$2:$A$5', null, 4),
|
||||
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, 'Worksheet!$A$7:$A$10', null, 4),
|
||||
];
|
||||
|
||||
// Set the Y-Axis values
|
||||
// Datatype
|
||||
// Cell reference for data
|
||||
// Format Code
|
||||
// Number of datapoints in series
|
||||
// Data values
|
||||
// Data Marker
|
||||
$dataSeriesValues = [
|
||||
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, 'Worksheet!$B$2:$B$5', null, 4),
|
||||
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, 'Worksheet!$B$7:$B$10', null, 4),
|
||||
];
|
||||
|
||||
// Set the Z-Axis values (bubble size)
|
||||
// Datatype
|
||||
// Cell reference for data
|
||||
// Format Code
|
||||
// Number of datapoints in series
|
||||
// Data values
|
||||
// Data Marker
|
||||
$dataSeriesBubbles = [
|
||||
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, 'Worksheet!$C$2:$C$5', null, 4),
|
||||
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, 'Worksheet!$C$7:$C$10', null, 4),
|
||||
];
|
||||
|
||||
// Build the dataseries
|
||||
$series = new DataSeries(
|
||||
DataSeries::TYPE_BUBBLECHART, // plotType
|
||||
null, // plotGrouping
|
||||
range(0, count($dataSeriesValues) - 1), // plotOrder
|
||||
$dataSeriesLabels, // plotLabel
|
||||
$dataSeriesCategories, // plotCategory
|
||||
$dataSeriesValues // plotValues
|
||||
);
|
||||
$series->setPlotBubbleSizes($dataSeriesBubbles);
|
||||
|
||||
// Set the series in the plot area
|
||||
$plotArea = new PlotArea(null, [$series]);
|
||||
// Set the chart legend
|
||||
$legend = new ChartLegend(ChartLegend::POSITION_RIGHT, null, false);
|
||||
|
||||
// Create the chart
|
||||
$chart = new Chart(
|
||||
'chart1', // name
|
||||
null, // title
|
||||
$legend, // legend
|
||||
$plotArea, // plotArea
|
||||
true, // plotVisibleOnly
|
||||
DataSeries::EMPTY_AS_GAP, // displayBlanksAs
|
||||
null, // xAxisLabel
|
||||
null // yAxisLabel
|
||||
);
|
||||
|
||||
// Set the position where the chart should appear in the worksheet
|
||||
$chart->setTopLeftPosition('E1');
|
||||
$chart->setBottomRightPosition('M15');
|
||||
|
||||
// Add the chart to the worksheet
|
||||
$worksheet->addChart($chart);
|
||||
$worksheet->getColumnDimension('A')->setAutoSize(true);
|
||||
$worksheet->getColumnDimension('B')->setAutoSize(true);
|
||||
$worksheet->getColumnDimension('C')->setAutoSize(true);
|
||||
|
||||
// Save Excel 2007 file
|
||||
$filename = $helper->getFilename(__FILE__);
|
||||
$writer = IOFactory::createWriter($spreadsheet, 'Xlsx');
|
||||
$writer->setIncludeCharts(true);
|
||||
$callStartTime = microtime(true);
|
||||
$writer->save($filename);
|
||||
$helper->logWrite($writer, $filename, $callStartTime);
|
||||
|
|
@ -0,0 +1,121 @@
|
|||
<?php
|
||||
|
||||
use PhpOffice\PhpSpreadsheet\Chart\Axis;
|
||||
use PhpOffice\PhpSpreadsheet\Chart\Chart;
|
||||
use PhpOffice\PhpSpreadsheet\Chart\DataSeries;
|
||||
use PhpOffice\PhpSpreadsheet\Chart\DataSeriesValues;
|
||||
use PhpOffice\PhpSpreadsheet\Chart\Legend as ChartLegend;
|
||||
use PhpOffice\PhpSpreadsheet\Chart\PlotArea;
|
||||
use PhpOffice\PhpSpreadsheet\Chart\Properties;
|
||||
use PhpOffice\PhpSpreadsheet\Chart\Title;
|
||||
use PhpOffice\PhpSpreadsheet\IOFactory;
|
||||
use PhpOffice\PhpSpreadsheet\Spreadsheet;
|
||||
|
||||
require __DIR__ . '/../Header.php';
|
||||
|
||||
$spreadsheet = new Spreadsheet();
|
||||
$worksheet = $spreadsheet->getActiveSheet();
|
||||
// changed data to simulate a trend chart - Xaxis are dates; Yaxis are 3 meausurements from each date
|
||||
$worksheet->fromArray(
|
||||
[
|
||||
['', 'metric1', 'metric2', 'metric3'],
|
||||
['=DATEVALUE("2021-01-01")', 12.1, 15.1, 21.1],
|
||||
['=DATEVALUE("2021-01-04")', 56.2, 73.2, 86.2],
|
||||
['=DATEVALUE("2021-01-07")', 52.2, 61.2, 69.2],
|
||||
['=DATEVALUE("2021-01-10")', 30.2, 32.2, 0.2],
|
||||
]
|
||||
);
|
||||
$worksheet->getStyle('A2:A5')->getNumberFormat()->setFormatCode(Properties::FORMAT_CODE_DATE_ISO8601);
|
||||
$worksheet->getColumnDimension('A')->setAutoSize(true);
|
||||
$worksheet->setSelectedCells('A1');
|
||||
|
||||
// Set the Labels for each data series we want to plot
|
||||
// Datatype
|
||||
// Cell reference for data
|
||||
// Format Code
|
||||
// Number of datapoints in series
|
||||
// Data values
|
||||
// Data Marker
|
||||
$dataSeriesLabels = [
|
||||
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$B$1', null, 1), // was 2010
|
||||
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$C$1', null, 1), // was 2011
|
||||
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$D$1', null, 1), // was 2012
|
||||
];
|
||||
// Set the X-Axis Labels
|
||||
// changed from STRING to NUMBER
|
||||
// added 2 additional x-axis values associated with each of the 3 metrics
|
||||
// added FORMATE_CODE_NUMBER
|
||||
$xAxisTickValues = [
|
||||
//new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$A$2:$A$5', null, 4), // Q1 to Q4
|
||||
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, 'Worksheet!$A$2:$A$5', Properties::FORMAT_CODE_DATE, 4),
|
||||
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, 'Worksheet!$A$2:$A$5', Properties::FORMAT_CODE_DATE, 4),
|
||||
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, 'Worksheet!$A$2:$A$5', Properties::FORMAT_CODE_DATE, 4),
|
||||
];
|
||||
// Set the Data values for each data series we want to plot
|
||||
// Datatype
|
||||
// Cell reference for data
|
||||
// Format Code
|
||||
// Number of datapoints in series
|
||||
// Data values
|
||||
// Data Marker
|
||||
// added FORMAT_CODE_NUMBER
|
||||
$dataSeriesValues = [
|
||||
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, 'Worksheet!$B$2:$B$5', Properties::FORMAT_CODE_NUMBER, 4),
|
||||
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, 'Worksheet!$C$2:$C$5', Properties::FORMAT_CODE_NUMBER, 4),
|
||||
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, 'Worksheet!$D$2:$D$5', Properties::FORMAT_CODE_NUMBER, 4),
|
||||
];
|
||||
// Added so that Xaxis shows dates instead of Excel-equivalent-year1900-numbers
|
||||
$xAxis = new Axis();
|
||||
//$xAxis->setAxisNumberProperties(Properties::FORMAT_CODE_DATE );
|
||||
$xAxis->setAxisNumberProperties(Properties::FORMAT_CODE_DATE_ISO8601, true);
|
||||
|
||||
// Build the dataseries
|
||||
$series = new DataSeries(
|
||||
DataSeries::TYPE_SCATTERCHART, // plotType
|
||||
null, // plotGrouping (Scatter charts don't have any grouping)
|
||||
range(0, count($dataSeriesValues) - 1), // plotOrder
|
||||
$dataSeriesLabels, // plotLabel
|
||||
$xAxisTickValues, // plotCategory
|
||||
$dataSeriesValues, // plotValues
|
||||
null, // plotDirection
|
||||
false, // smooth line
|
||||
//DataSeries::STYLE_LINEMARKER // plotStyle
|
||||
DataSeries::STYLE_MARKER // plotStyle
|
||||
);
|
||||
|
||||
// Set the series in the plot area
|
||||
$plotArea = new PlotArea(null, [$series]);
|
||||
// Set the chart legend
|
||||
$legend = new ChartLegend(ChartLegend::POSITION_TOPRIGHT, null, false);
|
||||
|
||||
$title = new Title('Test Scatter Trend Chart');
|
||||
$yAxisLabel = new Title('Value ($k)');
|
||||
|
||||
// Create the chart
|
||||
$chart = new Chart(
|
||||
'chart1', // name
|
||||
$title, // title
|
||||
$legend, // legend
|
||||
$plotArea, // plotArea
|
||||
true, // plotVisibleOnly
|
||||
DataSeries::EMPTY_AS_GAP, // displayBlanksAs
|
||||
null, // xAxisLabel
|
||||
$yAxisLabel, // yAxisLabel
|
||||
// added xAxis for correct date display
|
||||
$xAxis, // xAxis
|
||||
);
|
||||
|
||||
// Set the position where the chart should appear in the worksheet
|
||||
$chart->setTopLeftPosition('A7');
|
||||
$chart->setBottomRightPosition('P20');
|
||||
// Add the chart to the worksheet
|
||||
$worksheet->addChart($chart);
|
||||
|
||||
// Save Excel 2007 file
|
||||
$filename = $helper->getFilename(__FILE__);
|
||||
$writer = IOFactory::createWriter($spreadsheet, 'Xlsx');
|
||||
$writer->setIncludeCharts(true);
|
||||
$callStartTime = microtime(true);
|
||||
$writer->save($filename);
|
||||
$spreadsheet->disconnectWorksheets();
|
||||
$helper->logWrite($writer, $filename, $callStartTime);
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -3197,7 +3197,7 @@ class Calculation
|
|||
string $toSeparator
|
||||
): string {
|
||||
// Function Names
|
||||
$formula = preg_replace($from, $to, $formula);
|
||||
$formula = (string) preg_replace($from, $to, $formula);
|
||||
|
||||
// Temporarily adjust matrix separators so that they won't be confused with function arguments
|
||||
$formula = self::translateSeparator(';', '|', $formula, $inMatrixBracesLevel, self::FORMULA_OPEN_MATRIX_BRACE, self::FORMULA_CLOSE_MATRIX_BRACE);
|
||||
|
|
@ -4180,7 +4180,7 @@ class Calculation
|
|||
$length = strlen($val);
|
||||
|
||||
if (preg_match('/^' . self::CALCULATION_REGEXP_FUNCTION . '$/miu', $val, $matches)) {
|
||||
$val = preg_replace('/\s/u', '', $val);
|
||||
$val = (string) preg_replace('/\s/u', '', $val);
|
||||
if (isset(self::$phpSpreadsheetFunctions[strtoupper($matches[1])]) || isset(self::$controlFunctions[strtoupper($matches[1])])) { // it's a function
|
||||
$valToUpper = strtoupper($val);
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ class DateValue
|
|||
$baseYear = SharedDateHelper::getExcelCalendar();
|
||||
$dateValue = trim($dateValue ?? '', '"');
|
||||
// Strip any ordinals because they're allowed in Excel (English only)
|
||||
$dateValue = preg_replace('/(\d)(st|nd|rd|th)([ -\/])/Ui', '$1$3', $dateValue) ?? '';
|
||||
$dateValue = (string) preg_replace('/(\d)(st|nd|rd|th)([ -\/])/Ui', '$1$3', $dateValue);
|
||||
// Convert separators (/ . or space) to hyphens (should also handle dot used for ordinals in some countries, e.g. Denmark, Germany)
|
||||
$dateValue = str_replace(['/', '.', '-', ' '], ' ', $dateValue);
|
||||
|
||||
|
|
|
|||
|
|
@ -159,7 +159,7 @@ class Functions
|
|||
} elseif (!is_numeric($condition)) {
|
||||
if ($condition !== '""') { // Not an empty string
|
||||
// Escape any quotes in the string value
|
||||
$condition = preg_replace('/"/ui', '""', $condition);
|
||||
$condition = (string) preg_replace('/"/ui', '""', $condition);
|
||||
}
|
||||
$condition = Calculation::wrapResult(strtoupper($condition));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ class Helpers
|
|||
if ($namedRange !== null) {
|
||||
$workSheet = $namedRange->getWorkSheet();
|
||||
$sheetTitle = ($workSheet === null) ? '' : $workSheet->getTitle();
|
||||
$value = preg_replace('/^=/', '', $namedRange->getValue());
|
||||
$value = (string) preg_replace('/^=/', '', $namedRange->getValue());
|
||||
self::adjustSheetTitle($sheetTitle, $value);
|
||||
$cellAddress1 = $sheetTitle . $value;
|
||||
$cellAddress = $cellAddress1;
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ class RowColumnInformation
|
|||
|
||||
if (is_array($cellAddress)) {
|
||||
foreach ($cellAddress as $columnKey => $value) {
|
||||
$columnKey = preg_replace('/[^a-z]/i', '', $columnKey);
|
||||
$columnKey = (string) preg_replace('/[^a-z]/i', '', $columnKey);
|
||||
|
||||
return (int) Coordinate::columnIndexFromString($columnKey);
|
||||
}
|
||||
|
|
@ -66,8 +66,8 @@ class RowColumnInformation
|
|||
[, $cellAddress] = Worksheet::extractSheetTitle($cellAddress, true);
|
||||
if (strpos($cellAddress, ':') !== false) {
|
||||
[$startAddress, $endAddress] = explode(':', $cellAddress);
|
||||
$startAddress = preg_replace('/[^a-z]/i', '', $startAddress);
|
||||
$endAddress = preg_replace('/[^a-z]/i', '', $endAddress);
|
||||
$startAddress = (string) preg_replace('/[^a-z]/i', '', $startAddress);
|
||||
$endAddress = (string) preg_replace('/[^a-z]/i', '', $endAddress);
|
||||
|
||||
return range(
|
||||
(int) Coordinate::columnIndexFromString($startAddress),
|
||||
|
|
@ -75,7 +75,7 @@ class RowColumnInformation
|
|||
);
|
||||
}
|
||||
|
||||
$cellAddress = preg_replace('/[^a-z]/i', '', $cellAddress);
|
||||
$cellAddress = (string) preg_replace('/[^a-z]/i', '', $cellAddress);
|
||||
|
||||
return (int) Coordinate::columnIndexFromString($cellAddress);
|
||||
}
|
||||
|
|
@ -159,14 +159,13 @@ class RowColumnInformation
|
|||
[, $cellAddress] = Worksheet::extractSheetTitle($cellAddress, true);
|
||||
if (strpos($cellAddress, ':') !== false) {
|
||||
[$startAddress, $endAddress] = explode(':', $cellAddress);
|
||||
$startAddress = preg_replace('/\D/', '', $startAddress);
|
||||
$endAddress = preg_replace('/\D/', '', $endAddress);
|
||||
$startAddress = (string) preg_replace('/\D/', '', $startAddress);
|
||||
$endAddress = (string) preg_replace('/\D/', '', $endAddress);
|
||||
|
||||
return array_map(
|
||||
function ($value) {
|
||||
return [$value];
|
||||
},
|
||||
// @phpstan-ignore-next-line
|
||||
range($startAddress, $endAddress)
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -102,29 +102,27 @@ class Operations
|
|||
*/
|
||||
public static function product(...$args)
|
||||
{
|
||||
$args = array_filter(
|
||||
Functions::flattenArray($args),
|
||||
function ($value) {
|
||||
return $value !== null;
|
||||
}
|
||||
);
|
||||
|
||||
// Return value
|
||||
$returnValue = null;
|
||||
$returnValue = (count($args) === 0) ? 0.0 : 1.0;
|
||||
|
||||
// Loop through arguments
|
||||
foreach (Functions::flattenArray($args) as $arg) {
|
||||
foreach ($args as $arg) {
|
||||
// Is it a numeric value?
|
||||
if (is_numeric($arg)) {
|
||||
if ($returnValue === null) {
|
||||
$returnValue = $arg;
|
||||
} else {
|
||||
$returnValue *= $arg;
|
||||
}
|
||||
$returnValue *= $arg;
|
||||
} else {
|
||||
return ExcelError::VALUE();
|
||||
}
|
||||
}
|
||||
|
||||
// Return
|
||||
if ($returnValue === null) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return $returnValue;
|
||||
return (float) $returnValue;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ class Trim
|
|||
* @param mixed $stringValue String Value to check
|
||||
* Or can be an array of values
|
||||
*
|
||||
* @return null|array|string
|
||||
* @return array|string
|
||||
* If an array of values is passed as the argument, then the returned result will also be an array
|
||||
* with the same dimensions
|
||||
*/
|
||||
|
|
@ -26,7 +26,7 @@ class Trim
|
|||
|
||||
$stringValue = Helpers::extractString($stringValue);
|
||||
|
||||
return preg_replace('/[\\x00-\\x1f]/', '', "$stringValue");
|
||||
return (string) preg_replace('/[\\x00-\\x1f]/', '', "$stringValue");
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ class Axis extends Properties
|
|||
private $axisNumber = [
|
||||
'format' => self::FORMAT_CODE_GENERAL,
|
||||
'source_linked' => 1,
|
||||
'numeric' => null,
|
||||
];
|
||||
|
||||
/**
|
||||
|
|
@ -131,15 +132,26 @@ class Axis extends Properties
|
|||
'size' => null,
|
||||
];
|
||||
|
||||
private const NUMERIC_FORMAT = [
|
||||
Properties::FORMAT_CODE_NUMBER,
|
||||
Properties::FORMAT_CODE_DATE,
|
||||
];
|
||||
|
||||
/**
|
||||
* Get Series Data Type.
|
||||
*
|
||||
* @param mixed $format_code
|
||||
*/
|
||||
public function setAxisNumberProperties($format_code): void
|
||||
public function setAxisNumberProperties($format_code, ?bool $numeric = null): void
|
||||
{
|
||||
$this->axisNumber['format'] = (string) $format_code;
|
||||
$format = (string) $format_code;
|
||||
$this->axisNumber['format'] = $format;
|
||||
$this->axisNumber['source_linked'] = 0;
|
||||
if (is_bool($numeric)) {
|
||||
$this->axisNumber['numeric'] = $numeric;
|
||||
} elseif (in_array($format, self::NUMERIC_FORMAT, true)) {
|
||||
$this->axisNumber['numeric'] = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -162,6 +174,11 @@ class Axis extends Properties
|
|||
return (string) $this->axisNumber['source_linked'];
|
||||
}
|
||||
|
||||
public function getAxisIsNumericFormat(): bool
|
||||
{
|
||||
return (bool) $this->axisNumber['numeric'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Set Axis Options Properties.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -124,7 +124,7 @@ class Chart
|
|||
*
|
||||
* @var string
|
||||
*/
|
||||
private $bottomRightCellRef = 'A1';
|
||||
private $bottomRightCellRef = '';
|
||||
|
||||
/**
|
||||
* Bottom-Right X-Offset.
|
||||
|
|
@ -140,6 +140,21 @@ class Chart
|
|||
*/
|
||||
private $bottomRightYOffset = 10;
|
||||
|
||||
/** @var ?int */
|
||||
private $rotX;
|
||||
|
||||
/** @var ?int */
|
||||
private $rotY;
|
||||
|
||||
/** @var ?int */
|
||||
private $rAngAx;
|
||||
|
||||
/** @var ?int */
|
||||
private $perspective;
|
||||
|
||||
/** @var bool */
|
||||
private $oneCellAnchor = false;
|
||||
|
||||
/**
|
||||
* Create a new Chart.
|
||||
*
|
||||
|
|
@ -351,8 +366,9 @@ class Chart
|
|||
if ($this->yAxis !== null) {
|
||||
return $this->yAxis;
|
||||
}
|
||||
$this->yAxis = new Axis();
|
||||
|
||||
return new Axis();
|
||||
return $this->yAxis;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -365,8 +381,9 @@ class Chart
|
|||
if ($this->xAxis !== null) {
|
||||
return $this->xAxis;
|
||||
}
|
||||
$this->xAxis = new Axis();
|
||||
|
||||
return new Axis();
|
||||
return $this->xAxis;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -400,15 +417,15 @@ class Chart
|
|||
/**
|
||||
* Set the Top Left position for the chart.
|
||||
*
|
||||
* @param string $cell
|
||||
* @param string $cellAddress
|
||||
* @param int $xOffset
|
||||
* @param int $yOffset
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setTopLeftPosition($cell, $xOffset = null, $yOffset = null)
|
||||
public function setTopLeftPosition($cellAddress, $xOffset = null, $yOffset = null)
|
||||
{
|
||||
$this->topLeftCellRef = $cell;
|
||||
$this->topLeftCellRef = $cellAddress;
|
||||
if ($xOffset !== null) {
|
||||
$this->setTopLeftXOffset($xOffset);
|
||||
}
|
||||
|
|
@ -446,13 +463,13 @@ class Chart
|
|||
/**
|
||||
* Set the Top Left cell position for the chart.
|
||||
*
|
||||
* @param string $cell
|
||||
* @param string $cellAddress
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setTopLeftCell($cell)
|
||||
public function setTopLeftCell($cellAddress)
|
||||
{
|
||||
$this->topLeftCellRef = $cell;
|
||||
$this->topLeftCellRef = $cellAddress;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
|
@ -491,6 +508,11 @@ class Chart
|
|||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $xOffset
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setTopLeftXOffset($xOffset)
|
||||
{
|
||||
$this->topLeftXOffset = $xOffset;
|
||||
|
|
@ -498,11 +520,16 @@ class Chart
|
|||
return $this;
|
||||
}
|
||||
|
||||
public function getTopLeftXOffset()
|
||||
public function getTopLeftXOffset(): int
|
||||
{
|
||||
return $this->topLeftXOffset;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $yOffset
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setTopLeftYOffset($yOffset)
|
||||
{
|
||||
$this->topLeftYOffset = $yOffset;
|
||||
|
|
@ -510,7 +537,7 @@ class Chart
|
|||
return $this;
|
||||
}
|
||||
|
||||
public function getTopLeftYOffset()
|
||||
public function getTopLeftYOffset(): int
|
||||
{
|
||||
return $this->topLeftYOffset;
|
||||
}
|
||||
|
|
@ -518,15 +545,15 @@ class Chart
|
|||
/**
|
||||
* Set the Bottom Right position of the chart.
|
||||
*
|
||||
* @param string $cell
|
||||
* @param string $cellAddress
|
||||
* @param int $xOffset
|
||||
* @param int $yOffset
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setBottomRightPosition($cell, $xOffset = null, $yOffset = null)
|
||||
public function setBottomRightPosition($cellAddress = '', $xOffset = null, $yOffset = null)
|
||||
{
|
||||
$this->bottomRightCellRef = $cell;
|
||||
$this->bottomRightCellRef = $cellAddress;
|
||||
if ($xOffset !== null) {
|
||||
$this->setBottomRightXOffset($xOffset);
|
||||
}
|
||||
|
|
@ -551,19 +578,22 @@ class Chart
|
|||
];
|
||||
}
|
||||
|
||||
public function setBottomRightCell($cell)
|
||||
/**
|
||||
* Set the Bottom Right cell for the chart.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setBottomRightCell(string $cellAddress = '')
|
||||
{
|
||||
$this->bottomRightCellRef = $cell;
|
||||
$this->bottomRightCellRef = $cellAddress;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the cell address where the bottom right of the chart is fixed.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getBottomRightCell()
|
||||
public function getBottomRightCell(): string
|
||||
{
|
||||
return $this->bottomRightCellRef;
|
||||
}
|
||||
|
|
@ -602,6 +632,11 @@ class Chart
|
|||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $xOffset
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setBottomRightXOffset($xOffset)
|
||||
{
|
||||
$this->bottomRightXOffset = $xOffset;
|
||||
|
|
@ -609,11 +644,16 @@ class Chart
|
|||
return $this;
|
||||
}
|
||||
|
||||
public function getBottomRightXOffset()
|
||||
public function getBottomRightXOffset(): int
|
||||
{
|
||||
return $this->bottomRightXOffset;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $yOffset
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setBottomRightYOffset($yOffset)
|
||||
{
|
||||
$this->bottomRightYOffset = $yOffset;
|
||||
|
|
@ -621,7 +661,7 @@ class Chart
|
|||
return $this;
|
||||
}
|
||||
|
||||
public function getBottomRightYOffset()
|
||||
public function getBottomRightYOffset(): int
|
||||
{
|
||||
return $this->bottomRightYOffset;
|
||||
}
|
||||
|
|
@ -658,4 +698,64 @@ class Chart
|
|||
|
||||
return $renderer->render($outputDestination);
|
||||
}
|
||||
|
||||
public function getRotX(): ?int
|
||||
{
|
||||
return $this->rotX;
|
||||
}
|
||||
|
||||
public function setRotX(?int $rotX): self
|
||||
{
|
||||
$this->rotX = $rotX;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getRotY(): ?int
|
||||
{
|
||||
return $this->rotY;
|
||||
}
|
||||
|
||||
public function setRotY(?int $rotY): self
|
||||
{
|
||||
$this->rotY = $rotY;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getRAngAx(): ?int
|
||||
{
|
||||
return $this->rAngAx;
|
||||
}
|
||||
|
||||
public function setRAngAx(?int $rAngAx): self
|
||||
{
|
||||
$this->rAngAx = $rAngAx;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getPerspective(): ?int
|
||||
{
|
||||
return $this->perspective;
|
||||
}
|
||||
|
||||
public function setPerspective(?int $perspective): self
|
||||
{
|
||||
$this->perspective = $perspective;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getOneCellAnchor(): bool
|
||||
{
|
||||
return $this->oneCellAnchor;
|
||||
}
|
||||
|
||||
public function setOneCellAnchor(bool $oneCellAnchor): self
|
||||
{
|
||||
$this->oneCellAnchor = $oneCellAnchor;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -107,6 +107,13 @@ class DataSeries
|
|||
*/
|
||||
private $plotValues = [];
|
||||
|
||||
/**
|
||||
* Plot Bubble Sizes.
|
||||
*
|
||||
* @var DataSeriesValues[]
|
||||
*/
|
||||
private $plotBubbleSizes = [];
|
||||
|
||||
/**
|
||||
* Create a new DataSeries.
|
||||
*
|
||||
|
|
@ -339,6 +346,28 @@ class DataSeries
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Plot Bubble Sizes.
|
||||
*
|
||||
* @return DataSeriesValues[]
|
||||
*/
|
||||
public function getPlotBubbleSizes(): array
|
||||
{
|
||||
return $this->plotBubbleSizes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set Plot Bubble Sizes.
|
||||
*
|
||||
* @param DataSeriesValues[] $plotBubbleSizes
|
||||
*/
|
||||
public function setPlotBubbleSizes(array $plotBubbleSizes): self
|
||||
{
|
||||
$this->plotBubbleSizes = $plotBubbleSizes;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Number of Plot Series.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ class DataSeriesValues
|
|||
const DATASERIES_TYPE_STRING = 'String';
|
||||
const DATASERIES_TYPE_NUMBER = 'Number';
|
||||
|
||||
private static $dataTypeValues = [
|
||||
private const DATA_TYPE_VALUES = [
|
||||
self::DATASERIES_TYPE_STRING,
|
||||
self::DATASERIES_TYPE_NUMBER,
|
||||
];
|
||||
|
|
@ -27,7 +27,7 @@ class DataSeriesValues
|
|||
/**
|
||||
* Series Data Source.
|
||||
*
|
||||
* @var string
|
||||
* @var ?string
|
||||
*/
|
||||
private $dataSource;
|
||||
|
||||
|
|
@ -69,10 +69,13 @@ class DataSeriesValues
|
|||
/**
|
||||
* Fill color (can be array with colors if dataseries have custom colors).
|
||||
*
|
||||
* @var string|string[]
|
||||
* @var null|string|string[]
|
||||
*/
|
||||
private $fillColor;
|
||||
|
||||
/** @var string */
|
||||
private $schemeClr = '';
|
||||
|
||||
/**
|
||||
* Line Width.
|
||||
*
|
||||
|
|
@ -80,6 +83,12 @@ class DataSeriesValues
|
|||
*/
|
||||
private $lineWidth = 12700;
|
||||
|
||||
/** @var bool */
|
||||
private $scatterLines = true;
|
||||
|
||||
/** @var bool */
|
||||
private $bubble3D = false;
|
||||
|
||||
/**
|
||||
* Create a new DataSeriesValues object.
|
||||
*
|
||||
|
|
@ -90,8 +99,9 @@ class DataSeriesValues
|
|||
* @param mixed $dataValues
|
||||
* @param null|mixed $marker
|
||||
* @param null|string|string[] $fillColor
|
||||
* @param string $pointSize
|
||||
*/
|
||||
public function __construct($dataType = self::DATASERIES_TYPE_NUMBER, $dataSource = null, $formatCode = null, $pointCount = 0, $dataValues = [], $marker = null, $fillColor = null)
|
||||
public function __construct($dataType = self::DATASERIES_TYPE_NUMBER, $dataSource = null, $formatCode = null, $pointCount = 0, $dataValues = [], $marker = null, $fillColor = null, $pointSize = '3')
|
||||
{
|
||||
$this->setDataType($dataType);
|
||||
$this->dataSource = $dataSource;
|
||||
|
|
@ -100,6 +110,9 @@ class DataSeriesValues
|
|||
$this->dataValues = $dataValues;
|
||||
$this->pointMarker = $marker;
|
||||
$this->fillColor = $fillColor;
|
||||
if (is_numeric($pointSize)) {
|
||||
$this->pointSize = (int) $pointSize;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -126,7 +139,7 @@ class DataSeriesValues
|
|||
*/
|
||||
public function setDataType($dataType)
|
||||
{
|
||||
if (!in_array($dataType, self::$dataTypeValues)) {
|
||||
if (!in_array($dataType, self::DATA_TYPE_VALUES)) {
|
||||
throw new Exception('Invalid datatype for chart data series values');
|
||||
}
|
||||
$this->dataType = $dataType;
|
||||
|
|
@ -137,7 +150,7 @@ class DataSeriesValues
|
|||
/**
|
||||
* Get Series Data Source (formula).
|
||||
*
|
||||
* @return string
|
||||
* @return ?string
|
||||
*/
|
||||
public function getDataSource()
|
||||
{
|
||||
|
|
@ -147,7 +160,7 @@ class DataSeriesValues
|
|||
/**
|
||||
* Set Series Data Source (formula).
|
||||
*
|
||||
* @param string $dataSource
|
||||
* @param ?string $dataSource
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
|
|
@ -239,7 +252,7 @@ class DataSeriesValues
|
|||
/**
|
||||
* Get fill color.
|
||||
*
|
||||
* @return string|string[] HEX color or array with HEX colors
|
||||
* @return null|string|string[] HEX color or array with HEX colors
|
||||
*/
|
||||
public function getFillColor()
|
||||
{
|
||||
|
|
@ -249,7 +262,7 @@ class DataSeriesValues
|
|||
/**
|
||||
* Set fill color for series.
|
||||
*
|
||||
* @param string|string[] $color HEX color or array with HEX colors
|
||||
* @param null|string|string[] $color HEX color or array with HEX colors
|
||||
*
|
||||
* @return DataSeriesValues
|
||||
*/
|
||||
|
|
@ -260,7 +273,7 @@ class DataSeriesValues
|
|||
$this->validateColor($colorValue);
|
||||
}
|
||||
} else {
|
||||
$this->validateColor($color);
|
||||
$this->validateColor("$color");
|
||||
}
|
||||
$this->fillColor = $color;
|
||||
|
||||
|
|
@ -315,7 +328,7 @@ class DataSeriesValues
|
|||
*/
|
||||
public function isMultiLevelSeries()
|
||||
{
|
||||
if (count($this->dataValues) > 0) {
|
||||
if (!empty($this->dataValues)) {
|
||||
return is_array(array_values($this->dataValues)[0]);
|
||||
}
|
||||
|
||||
|
|
@ -379,7 +392,7 @@ class DataSeriesValues
|
|||
return $this;
|
||||
}
|
||||
|
||||
public function refresh(Worksheet $worksheet, $flatten = true): void
|
||||
public function refresh(Worksheet $worksheet, bool $flatten = true): void
|
||||
{
|
||||
if ($this->dataSource !== null) {
|
||||
$calcEngine = Calculation::getInstance($worksheet->getParent());
|
||||
|
|
@ -421,4 +434,40 @@ class DataSeriesValues
|
|||
$this->pointCount = count($this->dataValues);
|
||||
}
|
||||
}
|
||||
|
||||
public function getScatterLines(): bool
|
||||
{
|
||||
return $this->scatterLines;
|
||||
}
|
||||
|
||||
public function setScatterLines(bool $scatterLines): self
|
||||
{
|
||||
$this->scatterLines = $scatterLines;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getBubble3D(): bool
|
||||
{
|
||||
return $this->bubble3D;
|
||||
}
|
||||
|
||||
public function setBubble3D(bool $bubble3D): self
|
||||
{
|
||||
$this->bubble3D = $bubble3D;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getSchemeClr(): string
|
||||
{
|
||||
return $this->schemeClr;
|
||||
}
|
||||
|
||||
public function setSchemeClr(string $schemeClr): self
|
||||
{
|
||||
$this->schemeClr = $schemeClr;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@ abstract class Properties
|
|||
const FORMAT_CODE_CURRENCY = '$#,##0.00';
|
||||
const FORMAT_CODE_ACCOUNTING = '_($* #,##0.00_);_($* (#,##0.00);_($* "-"??_);_(@_)';
|
||||
const FORMAT_CODE_DATE = 'm/d/yyyy';
|
||||
const FORMAT_CODE_DATE_ISO8601 = 'yyyy-mm-dd';
|
||||
const FORMAT_CODE_TIME = '[$-F400]h:mm:ss AM/PM';
|
||||
const FORMAT_CODE_PERCENTAGE = '0.00%';
|
||||
const FORMAT_CODE_FRACTION = '# ?/?';
|
||||
|
|
|
|||
|
|
@ -171,9 +171,9 @@ class Properties
|
|||
if (is_numeric($timestamp)) {
|
||||
$timestamp = (float) $timestamp;
|
||||
} else {
|
||||
$timestamp = preg_replace('/[.][0-9]*$/', '', $timestamp) ?? '';
|
||||
$timestamp = preg_replace('/^(\\d{4})- (\\d)/', '$1-0$2', $timestamp) ?? '';
|
||||
$timestamp = preg_replace('/^(\\d{4}-\\d{2})- (\\d)/', '$1-0$2', $timestamp) ?? '';
|
||||
$timestamp = (string) preg_replace('/[.][0-9]*$/', '', $timestamp);
|
||||
$timestamp = (string) preg_replace('/^(\\d{4})- (\\d)/', '$1-0$2', $timestamp);
|
||||
$timestamp = (string) preg_replace('/^(\\d{4}-\\d{2})- (\\d)/', '$1-0$2', $timestamp);
|
||||
$timestamp = (float) (new DateTime($timestamp))->format('U');
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -642,7 +642,7 @@ class Html
|
|||
$text = ltrim($text);
|
||||
}
|
||||
// Trim any spaces immediately after a line break
|
||||
$text = preg_replace('/\n */mu', "\n", $text);
|
||||
$text = (string) preg_replace('/\n */mu', "\n", $text);
|
||||
$element->setText($text);
|
||||
}
|
||||
}
|
||||
|
|
@ -792,7 +792,7 @@ class Html
|
|||
|
||||
protected function parseTextNode(DOMText $textNode): void
|
||||
{
|
||||
$domText = preg_replace(
|
||||
$domText = (string) preg_replace(
|
||||
'/\s+/u',
|
||||
' ',
|
||||
str_replace(["\r", "\n"], ' ', $textNode->nodeValue ?? '')
|
||||
|
|
|
|||
|
|
@ -85,7 +85,7 @@ class Sample
|
|||
$file = str_replace(str_replace('\\', '/', $baseDir) . '/', '', str_replace('\\', '/', $file[0]));
|
||||
$info = pathinfo($file);
|
||||
$category = str_replace('_', ' ', $info['dirname']);
|
||||
$name = str_replace('_', ' ', preg_replace('/(|\.php)/', '', $info['filename']));
|
||||
$name = str_replace('_', ' ', (string) preg_replace('/(|\.php)/', '', $info['filename']));
|
||||
if (!in_array($category, ['.', 'boostrap', 'templates'])) {
|
||||
if (!isset($files[$category])) {
|
||||
$files[$category] = [];
|
||||
|
|
|
|||
|
|
@ -103,6 +103,9 @@ class Csv extends BaseReader
|
|||
*/
|
||||
protected $preserveNumericFormatting = false;
|
||||
|
||||
/** @var bool */
|
||||
private $preserveNullString = false;
|
||||
|
||||
/**
|
||||
* Create a new CSV Reader instance.
|
||||
*/
|
||||
|
|
@ -300,9 +303,11 @@ class Csv extends BaseReader
|
|||
}
|
||||
}
|
||||
|
||||
public function setTestAutoDetect(bool $value): void
|
||||
public function setTestAutoDetect(bool $value): self
|
||||
{
|
||||
$this->testAutodetect = $value;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
private function setAutoDetect(?string $value): ?string
|
||||
|
|
@ -390,7 +395,7 @@ class Csv extends BaseReader
|
|||
foreach ($rowData as $rowDatum) {
|
||||
$this->convertBoolean($rowDatum, $preserveBooleanString);
|
||||
$numberFormatMask = $this->convertFormattedNumber($rowDatum);
|
||||
if ($rowDatum !== '' && $this->readFilter->readCell($columnLetter, $currentRow)) {
|
||||
if (($rowDatum !== '' || $this->preserveNullString) && $this->readFilter->readCell($columnLetter, $currentRow)) {
|
||||
if ($this->contiguous) {
|
||||
if ($noOutputYet) {
|
||||
$noOutputYet = false;
|
||||
|
|
@ -625,4 +630,16 @@ class Csv extends BaseReader
|
|||
|
||||
return ($encoding === '') ? $dflt : $encoding;
|
||||
}
|
||||
|
||||
public function setPreserveNullString(bool $value): self
|
||||
{
|
||||
$this->preserveNullString = $value;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getPreserveNullString(): bool
|
||||
{
|
||||
return $this->preserveNullString;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -140,12 +140,12 @@ class Delimiter
|
|||
$line = $line . $newLine;
|
||||
|
||||
// Drop everything that is enclosed to avoid counting false positives in enclosures
|
||||
$line = preg_replace('/(' . $enclosure . '.*' . $enclosure . ')/Us', '', $line);
|
||||
$line = (string) preg_replace('/(' . $enclosure . '.*' . $enclosure . ')/Us', '', $line);
|
||||
|
||||
// See if we have any enclosures left in the line
|
||||
// if we still have an enclosure then we need to read the next line as well
|
||||
} while (preg_match('/(' . $enclosure . ')/', $line ?? '') > 0);
|
||||
} while (preg_match('/(' . $enclosure . ')/', $line) > 0);
|
||||
|
||||
return $line ?? false;
|
||||
return ($line !== '') ? $line : false;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -272,6 +272,11 @@ class Gnumeric extends BaseReader
|
|||
// name in line with the formula, not the reverse
|
||||
$this->spreadsheet->getActiveSheet()->setTitle($worksheetName, false, false);
|
||||
|
||||
$visibility = $sheetOrNull->attributes()['Visibility'] ?? 'GNM_SHEET_VISIBILITY_VISIBLE';
|
||||
if ((string) $visibility !== 'GNM_SHEET_VISIBILITY_VISIBLE') {
|
||||
$this->spreadsheet->getActiveSheet()->setSheetState(Worksheet::SHEETSTATE_HIDDEN);
|
||||
}
|
||||
|
||||
if (!$this->readDataOnly) {
|
||||
(new PageSetup($this->spreadsheet))
|
||||
->printInformation($sheet)
|
||||
|
|
|
|||
|
|
@ -619,7 +619,7 @@ class Html extends BaseReader
|
|||
{
|
||||
foreach ($element->childNodes as $child) {
|
||||
if ($child instanceof DOMText) {
|
||||
$domText = preg_replace('/\s+/u', ' ', trim($child->nodeValue ?? ''));
|
||||
$domText = (string) preg_replace('/\s+/u', ' ', trim($child->nodeValue ?? ''));
|
||||
if (is_string($cellContent)) {
|
||||
// simply append the text if the cell content is a plain text string
|
||||
$cellContent .= $domText;
|
||||
|
|
|
|||
|
|
@ -588,6 +588,7 @@ class Ods extends BaseReader
|
|||
break;
|
||||
}
|
||||
}
|
||||
$pageSettings->setVisibilityForWorksheet($spreadsheet->getActiveSheet(), $worksheetStyleName);
|
||||
$pageSettings->setPrintSettingsForWorksheet($spreadsheet->getActiveSheet(), $worksheetStyleName);
|
||||
++$worksheetID;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,17 +13,25 @@ class FormulaTranslator
|
|||
// Cell range 3-d reference
|
||||
// As we don't support 3-d ranges, we're just going to take a quick and dirty approach
|
||||
// and assume that the second worksheet reference is the same as the first
|
||||
$excelAddress = preg_replace('/\$?([^\.]+)\.([^\.]+):\$?([^\.]+)\.([^\.]+)/miu', '$1!$2:$4', $excelAddress);
|
||||
// Cell range reference in another sheet
|
||||
$excelAddress = preg_replace('/\$?([^\.]+)\.([^\.]+):\.([^\.]+)/miu', '$1!$2:$3', $excelAddress ?? '');
|
||||
// Cell reference in another sheet
|
||||
$excelAddress = preg_replace('/\$?([^\.]+)\.([^\.]+)/miu', '$1!$2', $excelAddress ?? '');
|
||||
// Cell range reference
|
||||
$excelAddress = preg_replace('/\.([^\.]+):\.([^\.]+)/miu', '$1:$2', $excelAddress ?? '');
|
||||
// Simple cell reference
|
||||
$excelAddress = preg_replace('/\.([^\.]+)/miu', '$1', $excelAddress ?? '');
|
||||
$excelAddress = (string) preg_replace(
|
||||
[
|
||||
'/\$?([^\.]+)\.([^\.]+):\$?([^\.]+)\.([^\.]+)/miu',
|
||||
'/\$?([^\.]+)\.([^\.]+):\.([^\.]+)/miu', // Cell range reference in another sheet
|
||||
'/\$?([^\.]+)\.([^\.]+)/miu', // Cell reference in another sheet
|
||||
'/\.([^\.]+):\.([^\.]+)/miu', // Cell range reference
|
||||
'/\.([^\.]+)/miu', // Simple cell reference
|
||||
],
|
||||
[
|
||||
'$1!$2:$4',
|
||||
'$1!$2:$3',
|
||||
'$1!$2',
|
||||
'$1:$2',
|
||||
'$1',
|
||||
],
|
||||
$excelAddress
|
||||
);
|
||||
|
||||
return $excelAddress ?? '';
|
||||
return $excelAddress;
|
||||
}
|
||||
|
||||
public static function convertToExcelFormulaValue(string $openOfficeFormula): string
|
||||
|
|
@ -37,16 +45,23 @@ class FormulaTranslator
|
|||
// Only replace in alternate array entries (i.e. non-quoted blocks)
|
||||
// so that conversion isn't done in string values
|
||||
if ($tKey = !$tKey) {
|
||||
// Cell range reference in another sheet
|
||||
$value = preg_replace('/\[\$?([^\.]+)\.([^\.]+):\.([^\.]+)\]/miu', '$1!$2:$3', $value);
|
||||
// Cell reference in another sheet
|
||||
$value = preg_replace('/\[\$?([^\.]+)\.([^\.]+)\]/miu', '$1!$2', $value ?? '');
|
||||
// Cell range reference
|
||||
$value = preg_replace('/\[\.([^\.]+):\.([^\.]+)\]/miu', '$1:$2', $value ?? '');
|
||||
// Simple cell reference
|
||||
$value = preg_replace('/\[\.([^\.]+)\]/miu', '$1', $value ?? '');
|
||||
$value = (string) preg_replace(
|
||||
[
|
||||
'/\[\$?([^\.]+)\.([^\.]+):\.([^\.]+)\]/miu', // Cell range reference in another sheet
|
||||
'/\[\$?([^\.]+)\.([^\.]+)\]/miu', // Cell reference in another sheet
|
||||
'/\[\.([^\.]+):\.([^\.]+)\]/miu', // Cell range reference
|
||||
'/\[\.([^\.]+)\]/miu', // Simple cell reference
|
||||
],
|
||||
[
|
||||
'$1!$2:$3',
|
||||
'$1!$2',
|
||||
'$1:$2',
|
||||
'$1',
|
||||
],
|
||||
$value
|
||||
);
|
||||
// Convert references to defined names/formulae
|
||||
$value = str_replace('$$', '', $value ?? '');
|
||||
$value = str_replace('$$', '', $value);
|
||||
|
||||
// Convert ODS function argument separators to Excel function argument separators
|
||||
$value = Calculation::translateSeparator(';', ',', $value, $inFunctionBracesLevel);
|
||||
|
|
@ -69,7 +84,7 @@ class FormulaTranslator
|
|||
Calculation::FORMULA_CLOSE_MATRIX_BRACE
|
||||
);
|
||||
|
||||
$value = preg_replace('/COM\.MICROSOFT\./ui', '', $value);
|
||||
$value = (string) preg_replace('/COM\.MICROSOFT\./ui', '', $value);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -8,16 +8,41 @@ use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
|
|||
|
||||
class PageSettings
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $officeNs;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $stylesNs;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $stylesFo;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $tableNs;
|
||||
|
||||
/**
|
||||
* @var string[]
|
||||
*/
|
||||
private $tableStylesCrossReference = [];
|
||||
|
||||
private $pageLayoutStyles = [];
|
||||
|
||||
/**
|
||||
* @var string[]
|
||||
*/
|
||||
private $masterStylesCrossReference = [];
|
||||
|
||||
/**
|
||||
* @var string[]
|
||||
*/
|
||||
private $masterPrintStylesCrossReference = [];
|
||||
|
||||
public function __construct(DOMDocument $styleDom)
|
||||
|
|
@ -32,6 +57,7 @@ class PageSettings
|
|||
$this->officeNs = $styleDom->lookupNamespaceUri('office');
|
||||
$this->stylesNs = $styleDom->lookupNamespaceUri('style');
|
||||
$this->stylesFo = $styleDom->lookupNamespaceUri('fo');
|
||||
$this->tableNs = $styleDom->lookupNamespaceUri('table');
|
||||
}
|
||||
|
||||
private function readPageSettingStyles(DOMDocument $styleDom): void
|
||||
|
|
@ -98,12 +124,33 @@ class PageSettings
|
|||
foreach ($styleXReferences as $styleXreferenceSet) {
|
||||
$styleXRefName = $styleXreferenceSet->getAttributeNS($this->stylesNs, 'name');
|
||||
$stylePageLayoutName = $styleXreferenceSet->getAttributeNS($this->stylesNs, 'master-page-name');
|
||||
$styleFamilyName = $styleXreferenceSet->getAttributeNS($this->stylesNs, 'family');
|
||||
if (!empty($styleFamilyName) && $styleFamilyName === 'table') {
|
||||
$styleVisibility = 'true';
|
||||
foreach ($styleXreferenceSet->getElementsByTagNameNS($this->stylesNs, 'table-properties') as $tableProperties) {
|
||||
$styleVisibility = $tableProperties->getAttributeNS($this->tableNs, 'display');
|
||||
}
|
||||
$this->tableStylesCrossReference[$styleXRefName] = $styleVisibility;
|
||||
}
|
||||
if (!empty($stylePageLayoutName)) {
|
||||
$this->masterStylesCrossReference[$styleXRefName] = $stylePageLayoutName;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function setVisibilityForWorksheet(Worksheet $worksheet, string $styleName): void
|
||||
{
|
||||
if (!array_key_exists($styleName, $this->tableStylesCrossReference)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$worksheet->setSheetState(
|
||||
$this->tableStylesCrossReference[$styleName] === 'false'
|
||||
? Worksheet::SHEETSTATE_HIDDEN
|
||||
: Worksheet::SHEETSTATE_VISIBLE
|
||||
);
|
||||
}
|
||||
|
||||
public function setPrintSettingsForWorksheet(Worksheet $worksheet, string $styleName): void
|
||||
{
|
||||
if (!array_key_exists($styleName, $this->masterStylesCrossReference)) {
|
||||
|
|
|
|||
|
|
@ -4521,17 +4521,17 @@ class Xls extends BaseReader
|
|||
|
||||
// first row '1' + last row '16384' indicates that full column is selected (apparently also in BIFF8!)
|
||||
if (preg_match('/^([A-Z]+1\:[A-Z]+)16384$/', $selectedCells)) {
|
||||
$selectedCells = preg_replace('/^([A-Z]+1\:[A-Z]+)16384$/', '${1}1048576', $selectedCells);
|
||||
$selectedCells = (string) preg_replace('/^([A-Z]+1\:[A-Z]+)16384$/', '${1}1048576', $selectedCells);
|
||||
}
|
||||
|
||||
// first row '1' + last row '65536' indicates that full column is selected
|
||||
if (preg_match('/^([A-Z]+1\:[A-Z]+)65536$/', $selectedCells)) {
|
||||
$selectedCells = preg_replace('/^([A-Z]+1\:[A-Z]+)65536$/', '${1}1048576', $selectedCells);
|
||||
$selectedCells = (string) preg_replace('/^([A-Z]+1\:[A-Z]+)65536$/', '${1}1048576', $selectedCells);
|
||||
}
|
||||
|
||||
// first column 'A' + last column 'IV' indicates that full row is selected
|
||||
if (preg_match('/^(A\d+\:)IV(\d+)$/', $selectedCells)) {
|
||||
$selectedCells = preg_replace('/^(A\d+\:)IV(\d+)$/', '${1}XFD${2}', $selectedCells);
|
||||
$selectedCells = (string) preg_replace('/^(A\d+\:)IV(\d+)$/', '${1}XFD${2}', $selectedCells);
|
||||
}
|
||||
|
||||
$this->phpSheet->setSelectedCells($selectedCells);
|
||||
|
|
|
|||
|
|
@ -158,6 +158,10 @@ class Xlsx extends BaseReader
|
|||
Namespaces::PURL_RELATIONSHIPS => Namespaces::PURL_DRAWING,
|
||||
];
|
||||
|
||||
private const REL_TO_CHART = [
|
||||
Namespaces::PURL_RELATIONSHIPS => Namespaces::PURL_CHART,
|
||||
];
|
||||
|
||||
/**
|
||||
* Reads names of the worksheets from a file, without parsing the whole file to a Spreadsheet object.
|
||||
*
|
||||
|
|
@ -227,7 +231,10 @@ class Xlsx extends BaseReader
|
|||
$worksheets = [];
|
||||
foreach ($relsWorkbook->Relationship as $elex) {
|
||||
$ele = self::getAttributes($elex);
|
||||
if ((string) $ele['Type'] === "$namespace/worksheet") {
|
||||
if (
|
||||
((string) $ele['Type'] === "$namespace/worksheet") ||
|
||||
((string) $ele['Type'] === "$namespace/chartsheet")
|
||||
) {
|
||||
$worksheets[(string) $ele['Id']] = $ele['Target'];
|
||||
}
|
||||
}
|
||||
|
|
@ -406,17 +413,21 @@ class Xlsx extends BaseReader
|
|||
|
||||
// Read the theme first, because we need the colour scheme when reading the styles
|
||||
[$workbookBasename, $xmlNamespaceBase] = $this->getWorkbookBaseName();
|
||||
$drawingNS = self::REL_TO_DRAWING[$xmlNamespaceBase] ?? Namespaces::DRAWINGML;
|
||||
$chartNS = self::REL_TO_CHART[$xmlNamespaceBase] ?? Namespaces::CHART;
|
||||
$wbRels = $this->loadZip("xl/_rels/${workbookBasename}.rels", Namespaces::RELATIONSHIPS);
|
||||
$theme = null;
|
||||
$this->styleReader = new Styles();
|
||||
foreach ($wbRels->Relationship as $relx) {
|
||||
$rel = self::getAttributes($relx);
|
||||
$relTarget = (string) $rel['Target'];
|
||||
if (substr($relTarget, 0, 4) === '/xl/') {
|
||||
$relTarget = substr($relTarget, 4);
|
||||
}
|
||||
switch ($rel['Type']) {
|
||||
case "$xmlNamespaceBase/theme":
|
||||
$themeOrderArray = ['lt1', 'dk1', 'lt2', 'dk2'];
|
||||
$themeOrderAdditional = count($themeOrderArray);
|
||||
$drawingNS = self::REL_TO_DRAWING[$xmlNamespaceBase] ?? Namespaces::DRAWINGML;
|
||||
|
||||
$xmlTheme = $this->loadZip("xl/{$relTarget}", $drawingNS);
|
||||
$xmlThemeName = self::getAttributes($xmlTheme);
|
||||
|
|
@ -513,6 +524,12 @@ class Xlsx extends BaseReader
|
|||
case Namespaces::PURL_WORKSHEET:
|
||||
$worksheets[(string) $ele['Id']] = $ele['Target'];
|
||||
|
||||
break;
|
||||
case Namespaces::CHARTSHEET:
|
||||
if ($this->includeCharts === true) {
|
||||
$worksheets[(string) $ele['Id']] = $ele['Target'];
|
||||
}
|
||||
|
||||
break;
|
||||
// a vbaProject ? (: some macros)
|
||||
case Namespaces::VBA:
|
||||
|
|
@ -691,6 +708,13 @@ class Xlsx extends BaseReader
|
|||
continue;
|
||||
}
|
||||
|
||||
$sheetReferenceId = (string) self::getArrayItem(self::getAttributes($eleSheet, $xmlNamespaceBase), 'id');
|
||||
if (isset($worksheets[$sheetReferenceId]) === false) {
|
||||
++$countSkippedSheets;
|
||||
$mapSheetId[$oldSheetId] = null;
|
||||
|
||||
continue;
|
||||
}
|
||||
// Map old sheet id in original workbook to new sheet id.
|
||||
// They will differ if loadSheetsOnly() is being used
|
||||
$mapSheetId[$oldSheetId] = $oldSheetId - $countSkippedSheets;
|
||||
|
|
@ -702,7 +726,8 @@ class Xlsx extends BaseReader
|
|||
// and we're simply bringing the worksheet name in line with the formula, not the
|
||||
// reverse
|
||||
$docSheet->setTitle((string) $eleSheetAttr['name'], false, false);
|
||||
$fileWorksheet = (string) $worksheets[(string) self::getArrayItem(self::getAttributes($eleSheet, $xmlNamespaceBase), 'id')];
|
||||
|
||||
$fileWorksheet = (string) $worksheets[$sheetReferenceId];
|
||||
$xmlSheet = $this->loadZipNoNamespace("$dir/$fileWorksheet", $mainNS);
|
||||
$xmlSheetNS = $this->loadZip("$dir/$fileWorksheet", $mainNS);
|
||||
|
||||
|
|
@ -1189,14 +1214,23 @@ class Xlsx extends BaseReader
|
|||
. '/_rels/'
|
||||
. basename($fileWorksheet)
|
||||
. '.rels';
|
||||
if (substr($drawingFilename, 0, 7) === 'xl//xl/') {
|
||||
$drawingFilename = substr($drawingFilename, 4);
|
||||
}
|
||||
if ($zip->locateName($drawingFilename)) {
|
||||
$relsWorksheet = $this->loadZipNoNamespace($drawingFilename, Namespaces::RELATIONSHIPS);
|
||||
$drawings = [];
|
||||
foreach ($relsWorksheet->Relationship as $ele) {
|
||||
if ((string) $ele['Type'] === "$xmlNamespaceBase/drawing") {
|
||||
$drawings[(string) $ele['Id']] = self::dirAdd("$dir/$fileWorksheet", $ele['Target']);
|
||||
$eleTarget = (string) $ele['Target'];
|
||||
if (substr($eleTarget, 0, 4) === '/xl/') {
|
||||
$drawings[(string) $ele['Id']] = substr($eleTarget, 1);
|
||||
} else {
|
||||
$drawings[(string) $ele['Id']] = self::dirAdd("$dir/$fileWorksheet", $ele['Target']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($xmlSheet->drawing && !$this->readDataOnly) {
|
||||
$unparsedDrawings = [];
|
||||
$fileDrawing = null;
|
||||
|
|
@ -1205,6 +1239,7 @@ class Xlsx extends BaseReader
|
|||
$fileDrawing = $drawings[$drawingRelId];
|
||||
$drawingFilename = dirname($fileDrawing) . '/_rels/' . basename($fileDrawing) . '.rels';
|
||||
$relsDrawing = $this->loadZipNoNamespace($drawingFilename, $xmlNamespaceBase);
|
||||
|
||||
$images = [];
|
||||
$hyperlinks = [];
|
||||
if ($relsDrawing && $relsDrawing->Relationship) {
|
||||
|
|
@ -1217,7 +1252,13 @@ class Xlsx extends BaseReader
|
|||
$images[(string) $ele['Id']] = self::dirAdd($fileDrawing, $ele['Target']);
|
||||
} elseif ($eleType === "$xmlNamespaceBase/chart") {
|
||||
if ($this->includeCharts) {
|
||||
$charts[self::dirAdd($fileDrawing, $ele['Target'])] = [
|
||||
$eleTarget = (string) $ele['Target'];
|
||||
if (substr($eleTarget, 0, 4) === '/xl/') {
|
||||
$index = substr($eleTarget, 1);
|
||||
} else {
|
||||
$index = self::dirAdd($fileDrawing, $eleTarget);
|
||||
}
|
||||
$charts[$index] = [
|
||||
'id' => (string) $ele['Id'],
|
||||
'sheet' => $docSheet->getTitle(),
|
||||
];
|
||||
|
|
@ -1225,6 +1266,7 @@ class Xlsx extends BaseReader
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
$xmlDrawing = $this->loadZipNoNamespace($fileDrawing, '');
|
||||
$xmlDrawingChildren = $xmlDrawing->children(Namespaces::SPREADSHEET_DRAWING);
|
||||
|
||||
|
|
@ -1308,6 +1350,7 @@ class Xlsx extends BaseReader
|
|||
'width' => $width,
|
||||
'height' => $height,
|
||||
'worksheetTitle' => $docSheet->getTitle(),
|
||||
'oneCellAnchor' => true,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
@ -1403,6 +1446,27 @@ class Xlsx extends BaseReader
|
|||
}
|
||||
}
|
||||
}
|
||||
if ($xmlDrawingChildren->absoluteAnchor) {
|
||||
foreach ($xmlDrawingChildren->absoluteAnchor as $absoluteAnchor) {
|
||||
if (($this->includeCharts) && ($absoluteAnchor->graphicFrame)) {
|
||||
$graphic = $absoluteAnchor->graphicFrame->children(Namespaces::DRAWINGML)->graphic;
|
||||
/** @var SimpleXMLElement $chartRef */
|
||||
$chartRef = $graphic->graphicData->children(Namespaces::CHART)->chart;
|
||||
$thisChart = (string) self::getAttributes($chartRef, $xmlNamespaceBase);
|
||||
$width = Drawing::EMUToPixels((int) self::getArrayItem(self::getAttributes($absoluteAnchor->ext), 'cx')[0]);
|
||||
$height = Drawing::EMUToPixels((int) self::getArrayItem(self::getAttributes($absoluteAnchor->ext), 'cy')[0]);
|
||||
|
||||
$chartDetails[$docSheet->getTitle() . '!' . $thisChart] = [
|
||||
'fromCoordinate' => 'A1',
|
||||
'fromOffsetX' => 0,
|
||||
'fromOffsetY' => 0,
|
||||
'width' => $width,
|
||||
'height' => $height,
|
||||
'worksheetTitle' => $docSheet->getTitle(),
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
if (empty($relsDrawing) && $xmlDrawing->count() == 0) {
|
||||
// Save Drawing without rels and children as unparsed
|
||||
$unparsedDrawings[$drawingRelId] = $xmlDrawing->asXML();
|
||||
|
|
@ -1422,7 +1486,7 @@ class Xlsx extends BaseReader
|
|||
}
|
||||
|
||||
// unparsed drawing AlternateContent
|
||||
$xmlAltDrawing = $this->loadZip($fileDrawing, Namespaces::COMPATIBILITY);
|
||||
$xmlAltDrawing = $this->loadZip((string) $fileDrawing, Namespaces::COMPATIBILITY);
|
||||
|
||||
if ($xmlAltDrawing->AlternateContent) {
|
||||
foreach ($xmlAltDrawing->AlternateContent as $alternateContent) {
|
||||
|
|
@ -1491,13 +1555,18 @@ class Xlsx extends BaseReader
|
|||
$rangeSets = preg_split("/('?(?:.*?)'?(?:![A-Z0-9]+:[A-Z0-9]+)),?/", $extractedRange, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE);
|
||||
$newRangeSets = [];
|
||||
foreach ($rangeSets as $rangeSet) {
|
||||
[$sheetName, $rangeSet] = Worksheet::extractSheetTitle($rangeSet, true);
|
||||
[, $rangeSet] = Worksheet::extractSheetTitle($rangeSet, true);
|
||||
if (empty($rangeSet)) {
|
||||
continue;
|
||||
}
|
||||
if (strpos($rangeSet, ':') === false) {
|
||||
$rangeSet = $rangeSet . ':' . $rangeSet;
|
||||
}
|
||||
$newRangeSets[] = str_replace('$', '', $rangeSet);
|
||||
}
|
||||
$docSheet->getPageSetup()->setPrintArea(implode(',', $newRangeSets));
|
||||
if (count($newRangeSets) > 0) {
|
||||
$docSheet->getPageSetup()->setPrintArea(implode(',', $newRangeSets));
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
|
|
@ -1601,17 +1670,26 @@ class Xlsx extends BaseReader
|
|||
if ($this->includeCharts) {
|
||||
$chartEntryRef = ltrim((string) $contentType['PartName'], '/');
|
||||
$chartElements = $this->loadZip($chartEntryRef);
|
||||
$objChart = Chart::readChart($chartElements, basename($chartEntryRef, '.xml'));
|
||||
|
||||
$chartReader = new Chart($chartNS, $drawingNS);
|
||||
$objChart = $chartReader->readChart($chartElements, basename($chartEntryRef, '.xml'));
|
||||
if (isset($charts[$chartEntryRef])) {
|
||||
$chartPositionRef = $charts[$chartEntryRef]['sheet'] . '!' . $charts[$chartEntryRef]['id'];
|
||||
if (isset($chartDetails[$chartPositionRef])) {
|
||||
$excel->getSheetByName($charts[$chartEntryRef]['sheet'])->addChart($objChart);
|
||||
$objChart->setWorksheet($excel->getSheetByName($charts[$chartEntryRef]['sheet']));
|
||||
$objChart->setTopLeftPosition($chartDetails[$chartPositionRef]['fromCoordinate'], $chartDetails[$chartPositionRef]['fromOffsetX'], $chartDetails[$chartPositionRef]['fromOffsetY']);
|
||||
// For oneCellAnchor or absoluteAnchor positioned charts,
|
||||
// toCoordinate is not in the data. Does it need to be calculated?
|
||||
if (array_key_exists('toCoordinate', $chartDetails[$chartPositionRef])) {
|
||||
// For oneCellAnchor positioned charts, toCoordinate is not in the data. Does it need to be calculated?
|
||||
// twoCellAnchor
|
||||
$objChart->setTopLeftPosition($chartDetails[$chartPositionRef]['fromCoordinate'], $chartDetails[$chartPositionRef]['fromOffsetX'], $chartDetails[$chartPositionRef]['fromOffsetY']);
|
||||
$objChart->setBottomRightPosition($chartDetails[$chartPositionRef]['toCoordinate'], $chartDetails[$chartPositionRef]['toOffsetX'], $chartDetails[$chartPositionRef]['toOffsetY']);
|
||||
} else {
|
||||
// oneCellAnchor or absoluteAnchor (e.g. Chart sheet)
|
||||
$objChart->setTopLeftPosition($chartDetails[$chartPositionRef]['fromCoordinate'], $chartDetails[$chartPositionRef]['fromOffsetX'], $chartDetails[$chartPositionRef]['fromOffsetY']);
|
||||
$objChart->setBottomRightPosition('', $chartDetails[$chartPositionRef]['width'], $chartDetails[$chartPositionRef]['height']);
|
||||
if (array_key_exists('oneCellAnchor', $chartDetails[$chartPositionRef])) {
|
||||
$objChart->setOneCellAnchor($chartDetails[$chartPositionRef]['oneCellAnchor']);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1771,12 +1849,17 @@ class Xlsx extends BaseReader
|
|||
return $array[$key] ?? null;
|
||||
}
|
||||
|
||||
private static function dirAdd($base, $add)
|
||||
private static function dirAdd($base, $add): string
|
||||
{
|
||||
return preg_replace('~[^/]+/\.\./~', '', dirname($base) . "/$add");
|
||||
$add = "$add";
|
||||
if (substr($add, 0, 4) === '/xl/') {
|
||||
$add = substr($add, 4);
|
||||
}
|
||||
|
||||
return (string) preg_replace('~[^/]+/\.\./~', '', dirname($base) . "/$add");
|
||||
}
|
||||
|
||||
private static function toCSSArray($style)
|
||||
private static function toCSSArray($style): array
|
||||
{
|
||||
$style = self::stripWhiteSpaceFromStyleString($style);
|
||||
|
||||
|
|
@ -1807,12 +1890,12 @@ class Xlsx extends BaseReader
|
|||
return $style;
|
||||
}
|
||||
|
||||
public static function stripWhiteSpaceFromStyleString($string)
|
||||
public static function stripWhiteSpaceFromStyleString($string): string
|
||||
{
|
||||
return trim(str_replace(["\r", "\n", ' '], '', $string), ';');
|
||||
}
|
||||
|
||||
private static function boolean($value)
|
||||
private static function boolean($value): bool
|
||||
{
|
||||
if (is_object($value)) {
|
||||
$value = (string) $value;
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ class AutoFilter
|
|||
public function load(): void
|
||||
{
|
||||
// Remove all "$" in the auto filter range
|
||||
$autoFilterRange = preg_replace('/\$/', '', $this->worksheetXml->autoFilter['ref'] ?? '');
|
||||
$autoFilterRange = (string) preg_replace('/\$/', '', $this->worksheetXml->autoFilter['ref'] ?? '');
|
||||
if (strpos($autoFilterRange, ':') !== false) {
|
||||
$this->readAutoFilter($autoFilterRange, $this->worksheetXml);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,6 +16,18 @@ use SimpleXMLElement;
|
|||
|
||||
class Chart
|
||||
{
|
||||
/** @var string */
|
||||
private $cNamespace;
|
||||
|
||||
/** @var string */
|
||||
private $aNamespace;
|
||||
|
||||
public function __construct(string $cNamespace = Namespaces::CHART, string $aNamespace = Namespaces::DRAWINGML)
|
||||
{
|
||||
$this->cNamespace = $cNamespace;
|
||||
$this->aNamespace = $aNamespace;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @param string $format
|
||||
|
|
@ -25,7 +37,7 @@ class Chart
|
|||
private static function getAttribute(SimpleXMLElement $component, $name, $format)
|
||||
{
|
||||
$attributes = $component->attributes();
|
||||
if (isset($attributes[$name])) {
|
||||
if (@isset($attributes[$name])) {
|
||||
if ($format == 'string') {
|
||||
return (string) $attributes[$name];
|
||||
} elseif ($format == 'integer') {
|
||||
|
|
@ -42,58 +54,56 @@ class Chart
|
|||
return null;
|
||||
}
|
||||
|
||||
private static function readColor($color, $background = false)
|
||||
{
|
||||
if (isset($color['rgb'])) {
|
||||
return (string) $color['rgb'];
|
||||
} elseif (isset($color['indexed'])) {
|
||||
return Color::indexedColor($color['indexed'] - 7, $background)->getARGB();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $chartName
|
||||
*
|
||||
* @return \PhpOffice\PhpSpreadsheet\Chart\Chart
|
||||
*/
|
||||
public static function readChart(SimpleXMLElement $chartElements, $chartName)
|
||||
public function readChart(SimpleXMLElement $chartElements, $chartName)
|
||||
{
|
||||
$namespacesChartMeta = $chartElements->getNamespaces(true);
|
||||
$chartElementsC = $chartElements->children($namespacesChartMeta['c']);
|
||||
$chartElementsC = $chartElements->children($this->cNamespace);
|
||||
|
||||
$XaxisLabel = $YaxisLabel = $legend = $title = null;
|
||||
$dispBlanksAs = $plotVisOnly = null;
|
||||
$plotArea = null;
|
||||
$rotX = $rotY = $rAngAx = $perspective = null;
|
||||
foreach ($chartElementsC as $chartElementKey => $chartElement) {
|
||||
switch ($chartElementKey) {
|
||||
case 'chart':
|
||||
foreach ($chartElement as $chartDetailsKey => $chartDetails) {
|
||||
$chartDetailsC = $chartDetails->children($namespacesChartMeta['c']);
|
||||
$chartDetailsC = $chartDetails->children($this->cNamespace);
|
||||
switch ($chartDetailsKey) {
|
||||
case 'view3D':
|
||||
$rotX = self::getAttribute($chartDetails->rotX, 'val', 'integer');
|
||||
$rotY = self::getAttribute($chartDetails->rotY, 'val', 'integer');
|
||||
$rAngAx = self::getAttribute($chartDetails->rAngAx, 'val', 'integer');
|
||||
$perspective = self::getAttribute($chartDetails->perspective, 'val', 'integer');
|
||||
|
||||
break;
|
||||
case 'plotArea':
|
||||
$plotAreaLayout = $XaxisLabel = $YaxisLabel = null;
|
||||
$plotSeries = $plotAttributes = [];
|
||||
foreach ($chartDetails as $chartDetailKey => $chartDetail) {
|
||||
switch ($chartDetailKey) {
|
||||
case 'layout':
|
||||
$plotAreaLayout = self::chartLayoutDetails($chartDetail, $namespacesChartMeta);
|
||||
$plotAreaLayout = $this->chartLayoutDetails($chartDetail);
|
||||
|
||||
break;
|
||||
case 'catAx':
|
||||
if (isset($chartDetail->title)) {
|
||||
$XaxisLabel = self::chartTitle($chartDetail->title->children($namespacesChartMeta['c']), $namespacesChartMeta);
|
||||
$XaxisLabel = $this->chartTitle($chartDetail->title->children($this->cNamespace));
|
||||
}
|
||||
|
||||
break;
|
||||
case 'dateAx':
|
||||
if (isset($chartDetail->title)) {
|
||||
$XaxisLabel = self::chartTitle($chartDetail->title->children($namespacesChartMeta['c']), $namespacesChartMeta);
|
||||
$XaxisLabel = $this->chartTitle($chartDetail->title->children($this->cNamespace));
|
||||
}
|
||||
|
||||
break;
|
||||
case 'valAx':
|
||||
if (isset($chartDetail->title, $chartDetail->axPos)) {
|
||||
$axisLabel = self::chartTitle($chartDetail->title->children($namespacesChartMeta['c']), $namespacesChartMeta);
|
||||
$axisLabel = $this->chartTitle($chartDetail->title->children($this->cNamespace));
|
||||
$axPos = self::getAttribute($chartDetail->axPos, 'val', 'string');
|
||||
|
||||
switch ($axPos) {
|
||||
|
|
@ -114,70 +124,72 @@ class Chart
|
|||
case 'barChart':
|
||||
case 'bar3DChart':
|
||||
$barDirection = self::getAttribute($chartDetail->barDir, 'val', 'string');
|
||||
$plotSer = self::chartDataSeries($chartDetail, $namespacesChartMeta, $chartDetailKey);
|
||||
$plotSer->setPlotDirection($barDirection);
|
||||
$plotSer = $this->chartDataSeries($chartDetail, $chartDetailKey);
|
||||
$plotSer->setPlotDirection("$barDirection");
|
||||
$plotSeries[] = $plotSer;
|
||||
$plotAttributes = self::readChartAttributes($chartDetail);
|
||||
$plotAttributes = $this->readChartAttributes($chartDetail);
|
||||
|
||||
break;
|
||||
case 'lineChart':
|
||||
case 'line3DChart':
|
||||
$plotSeries[] = self::chartDataSeries($chartDetail, $namespacesChartMeta, $chartDetailKey);
|
||||
$plotAttributes = self::readChartAttributes($chartDetail);
|
||||
$plotSeries[] = $this->chartDataSeries($chartDetail, $chartDetailKey);
|
||||
$plotAttributes = $this->readChartAttributes($chartDetail);
|
||||
|
||||
break;
|
||||
case 'areaChart':
|
||||
case 'area3DChart':
|
||||
$plotSeries[] = self::chartDataSeries($chartDetail, $namespacesChartMeta, $chartDetailKey);
|
||||
$plotAttributes = self::readChartAttributes($chartDetail);
|
||||
$plotSeries[] = $this->chartDataSeries($chartDetail, $chartDetailKey);
|
||||
$plotAttributes = $this->readChartAttributes($chartDetail);
|
||||
|
||||
break;
|
||||
case 'doughnutChart':
|
||||
case 'pieChart':
|
||||
case 'pie3DChart':
|
||||
$explosion = isset($chartDetail->ser->explosion);
|
||||
$plotSer = self::chartDataSeries($chartDetail, $namespacesChartMeta, $chartDetailKey);
|
||||
$plotSer->setPlotStyle($explosion);
|
||||
$plotSer = $this->chartDataSeries($chartDetail, $chartDetailKey);
|
||||
$plotSer->setPlotStyle("$explosion");
|
||||
$plotSeries[] = $plotSer;
|
||||
$plotAttributes = self::readChartAttributes($chartDetail);
|
||||
$plotAttributes = $this->readChartAttributes($chartDetail);
|
||||
|
||||
break;
|
||||
case 'scatterChart':
|
||||
/** @var string */
|
||||
$scatterStyle = self::getAttribute($chartDetail->scatterStyle, 'val', 'string');
|
||||
$plotSer = self::chartDataSeries($chartDetail, $namespacesChartMeta, $chartDetailKey);
|
||||
$plotSer = $this->chartDataSeries($chartDetail, $chartDetailKey);
|
||||
$plotSer->setPlotStyle($scatterStyle);
|
||||
$plotSeries[] = $plotSer;
|
||||
$plotAttributes = self::readChartAttributes($chartDetail);
|
||||
$plotAttributes = $this->readChartAttributes($chartDetail);
|
||||
|
||||
break;
|
||||
case 'bubbleChart':
|
||||
$bubbleScale = self::getAttribute($chartDetail->bubbleScale, 'val', 'integer');
|
||||
$plotSer = self::chartDataSeries($chartDetail, $namespacesChartMeta, $chartDetailKey);
|
||||
$plotSer->setPlotStyle($bubbleScale);
|
||||
$plotSer = $this->chartDataSeries($chartDetail, $chartDetailKey);
|
||||
$plotSer->setPlotStyle("$bubbleScale");
|
||||
$plotSeries[] = $plotSer;
|
||||
$plotAttributes = self::readChartAttributes($chartDetail);
|
||||
$plotAttributes = $this->readChartAttributes($chartDetail);
|
||||
|
||||
break;
|
||||
case 'radarChart':
|
||||
/** @var string */
|
||||
$radarStyle = self::getAttribute($chartDetail->radarStyle, 'val', 'string');
|
||||
$plotSer = self::chartDataSeries($chartDetail, $namespacesChartMeta, $chartDetailKey);
|
||||
$plotSer = $this->chartDataSeries($chartDetail, $chartDetailKey);
|
||||
$plotSer->setPlotStyle($radarStyle);
|
||||
$plotSeries[] = $plotSer;
|
||||
$plotAttributes = self::readChartAttributes($chartDetail);
|
||||
$plotAttributes = $this->readChartAttributes($chartDetail);
|
||||
|
||||
break;
|
||||
case 'surfaceChart':
|
||||
case 'surface3DChart':
|
||||
$wireFrame = self::getAttribute($chartDetail->wireframe, 'val', 'boolean');
|
||||
$plotSer = self::chartDataSeries($chartDetail, $namespacesChartMeta, $chartDetailKey);
|
||||
$plotSer->setPlotStyle($wireFrame);
|
||||
$plotSer = $this->chartDataSeries($chartDetail, $chartDetailKey);
|
||||
$plotSer->setPlotStyle("$wireFrame");
|
||||
$plotSeries[] = $plotSer;
|
||||
$plotAttributes = self::readChartAttributes($chartDetail);
|
||||
$plotAttributes = $this->readChartAttributes($chartDetail);
|
||||
|
||||
break;
|
||||
case 'stockChart':
|
||||
$plotSeries[] = self::chartDataSeries($chartDetail, $namespacesChartMeta, $chartDetailKey);
|
||||
$plotAttributes = self::readChartAttributes($plotAreaLayout);
|
||||
$plotSeries[] = $this->chartDataSeries($chartDetail, $chartDetailKey);
|
||||
$plotAttributes = $this->readChartAttributes($plotAreaLayout);
|
||||
|
||||
break;
|
||||
}
|
||||
|
|
@ -186,7 +198,7 @@ class Chart
|
|||
$plotAreaLayout = new Layout();
|
||||
}
|
||||
$plotArea = new PlotArea($plotAreaLayout, $plotSeries);
|
||||
self::setChartAttributes($plotAreaLayout, $plotAttributes);
|
||||
$this->setChartAttributes($plotAreaLayout, $plotAttributes);
|
||||
|
||||
break;
|
||||
case 'plotVisOnly':
|
||||
|
|
@ -198,7 +210,7 @@ class Chart
|
|||
|
||||
break;
|
||||
case 'title':
|
||||
$title = self::chartTitle($chartDetails, $namespacesChartMeta);
|
||||
$title = $this->chartTitle($chartDetails);
|
||||
|
||||
break;
|
||||
case 'legend':
|
||||
|
|
@ -216,42 +228,54 @@ class Chart
|
|||
|
||||
break;
|
||||
case 'layout':
|
||||
$legendLayout = self::chartLayoutDetails($chartDetail, $namespacesChartMeta);
|
||||
$legendLayout = $this->chartLayoutDetails($chartDetail);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
$legend = new Legend($legendPos, $legendLayout, $legendOverlay);
|
||||
$legend = new Legend("$legendPos", $legendLayout, (bool) $legendOverlay);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
$chart = new \PhpOffice\PhpSpreadsheet\Chart\Chart($chartName, $title, $legend, $plotArea, $plotVisOnly, $dispBlanksAs, $XaxisLabel, $YaxisLabel);
|
||||
$chart = new \PhpOffice\PhpSpreadsheet\Chart\Chart($chartName, $title, $legend, $plotArea, $plotVisOnly, (string) $dispBlanksAs, $XaxisLabel, $YaxisLabel);
|
||||
if (is_int($rotX)) {
|
||||
$chart->setRotX($rotX);
|
||||
}
|
||||
if (is_int($rotY)) {
|
||||
$chart->setRotY($rotY);
|
||||
}
|
||||
if (is_int($rAngAx)) {
|
||||
$chart->setRAngAx($rAngAx);
|
||||
}
|
||||
if (is_int($perspective)) {
|
||||
$chart->setPerspective($perspective);
|
||||
}
|
||||
|
||||
return $chart;
|
||||
}
|
||||
|
||||
private static function chartTitle(SimpleXMLElement $titleDetails, array $namespacesChartMeta)
|
||||
private function chartTitle(SimpleXMLElement $titleDetails): Title
|
||||
{
|
||||
$caption = [];
|
||||
$titleLayout = null;
|
||||
foreach ($titleDetails as $titleDetailKey => $chartDetail) {
|
||||
switch ($titleDetailKey) {
|
||||
case 'tx':
|
||||
$titleDetails = $chartDetail->rich->children($namespacesChartMeta['a']);
|
||||
$titleDetails = $chartDetail->rich->children($this->aNamespace);
|
||||
foreach ($titleDetails as $titleKey => $titleDetail) {
|
||||
switch ($titleKey) {
|
||||
case 'p':
|
||||
$titleDetailPart = $titleDetail->children($namespacesChartMeta['a']);
|
||||
$caption[] = self::parseRichText($titleDetailPart);
|
||||
$titleDetailPart = $titleDetail->children($this->aNamespace);
|
||||
$caption[] = $this->parseRichText($titleDetailPart);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
case 'layout':
|
||||
$titleLayout = self::chartLayoutDetails($chartDetail, $namespacesChartMeta);
|
||||
$titleLayout = $this->chartLayoutDetails($chartDetail);
|
||||
|
||||
break;
|
||||
}
|
||||
|
|
@ -260,12 +284,12 @@ class Chart
|
|||
return new Title($caption, $titleLayout);
|
||||
}
|
||||
|
||||
private static function chartLayoutDetails($chartDetail, $namespacesChartMeta)
|
||||
private function chartLayoutDetails(SimpleXMLElement $chartDetail): ?Layout
|
||||
{
|
||||
if (!isset($chartDetail->manualLayout)) {
|
||||
return null;
|
||||
}
|
||||
$details = $chartDetail->manualLayout->children($namespacesChartMeta['c']);
|
||||
$details = $chartDetail->manualLayout->children($this->cNamespace);
|
||||
if ($details === null) {
|
||||
return null;
|
||||
}
|
||||
|
|
@ -277,13 +301,13 @@ class Chart
|
|||
return new Layout($layout);
|
||||
}
|
||||
|
||||
private static function chartDataSeries($chartDetail, $namespacesChartMeta, $plotType)
|
||||
private function chartDataSeries(SimpleXMLElement $chartDetail, string $plotType): DataSeries
|
||||
{
|
||||
$multiSeriesType = null;
|
||||
$smoothLine = false;
|
||||
$seriesLabel = $seriesCategory = $seriesValues = $plotOrder = [];
|
||||
$seriesLabel = $seriesCategory = $seriesValues = $plotOrder = $seriesBubbles = [];
|
||||
|
||||
$seriesDetailSet = $chartDetail->children($namespacesChartMeta['c']);
|
||||
$seriesDetailSet = $chartDetail->children($this->cNamespace);
|
||||
foreach ($seriesDetailSet as $seriesDetailKey => $seriesDetails) {
|
||||
switch ($seriesDetailKey) {
|
||||
case 'grouping':
|
||||
|
|
@ -293,6 +317,12 @@ class Chart
|
|||
case 'ser':
|
||||
$marker = null;
|
||||
$seriesIndex = '';
|
||||
$srgbClr = null;
|
||||
$lineWidth = null;
|
||||
$pointSize = null;
|
||||
$noFill = false;
|
||||
$schemeClr = '';
|
||||
$bubble3D = false;
|
||||
foreach ($seriesDetails as $seriesKey => $seriesDetail) {
|
||||
switch ($seriesKey) {
|
||||
case 'idx':
|
||||
|
|
@ -305,11 +335,32 @@ class Chart
|
|||
|
||||
break;
|
||||
case 'tx':
|
||||
$seriesLabel[$seriesIndex] = self::chartDataSeriesValueSet($seriesDetail, $namespacesChartMeta);
|
||||
$seriesLabel[$seriesIndex] = $this->chartDataSeriesValueSet($seriesDetail);
|
||||
|
||||
break;
|
||||
case 'spPr':
|
||||
$children = $seriesDetail->children($this->aNamespace);
|
||||
$ln = $children->ln;
|
||||
$lineWidth = self::getAttribute($ln, 'w', 'string');
|
||||
if (is_countable($ln->noFill) && count($ln->noFill) === 1) {
|
||||
$noFill = true;
|
||||
}
|
||||
$sf = $children->solidFill->schemeClr;
|
||||
if ($sf) {
|
||||
$schemeClr = self::getAttribute($sf, 'val', 'string');
|
||||
}
|
||||
|
||||
break;
|
||||
case 'marker':
|
||||
$marker = self::getAttribute($seriesDetail->symbol, 'val', 'string');
|
||||
$pointSize = self::getAttribute($seriesDetail->size, 'val', 'string');
|
||||
$pointSize = is_numeric($pointSize) ? ((int) $pointSize) : null;
|
||||
if (count($seriesDetail->spPr) === 1) {
|
||||
$ln = $seriesDetail->spPr->children($this->aNamespace);
|
||||
if (count($ln->solidFill) === 1) {
|
||||
$srgbClr = self::getAttribute($ln->solidFill->srgbClr, 'val', 'string');
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
case 'smooth':
|
||||
|
|
@ -317,37 +368,95 @@ class Chart
|
|||
|
||||
break;
|
||||
case 'cat':
|
||||
$seriesCategory[$seriesIndex] = self::chartDataSeriesValueSet($seriesDetail, $namespacesChartMeta);
|
||||
$seriesCategory[$seriesIndex] = $this->chartDataSeriesValueSet($seriesDetail);
|
||||
|
||||
break;
|
||||
case 'val':
|
||||
$seriesValues[$seriesIndex] = self::chartDataSeriesValueSet($seriesDetail, $namespacesChartMeta, $marker);
|
||||
$seriesValues[$seriesIndex] = $this->chartDataSeriesValueSet($seriesDetail, "$marker", "$srgbClr", "$pointSize");
|
||||
|
||||
break;
|
||||
case 'xVal':
|
||||
$seriesCategory[$seriesIndex] = self::chartDataSeriesValueSet($seriesDetail, $namespacesChartMeta, $marker);
|
||||
$seriesCategory[$seriesIndex] = $this->chartDataSeriesValueSet($seriesDetail, "$marker", "$srgbClr", "$pointSize");
|
||||
|
||||
break;
|
||||
case 'yVal':
|
||||
$seriesValues[$seriesIndex] = self::chartDataSeriesValueSet($seriesDetail, $namespacesChartMeta, $marker);
|
||||
$seriesValues[$seriesIndex] = $this->chartDataSeriesValueSet($seriesDetail, "$marker", "$srgbClr", "$pointSize");
|
||||
|
||||
break;
|
||||
case 'bubbleSize':
|
||||
$seriesBubbles[$seriesIndex] = $this->chartDataSeriesValueSet($seriesDetail, "$marker", "$srgbClr", "$pointSize");
|
||||
|
||||
break;
|
||||
case 'bubble3D':
|
||||
$bubble3D = self::getAttribute($seriesDetail, 'val', 'boolean');
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ($noFill) {
|
||||
if (isset($seriesLabel[$seriesIndex])) {
|
||||
$seriesLabel[$seriesIndex]->setScatterLines(false);
|
||||
}
|
||||
if (isset($seriesCategory[$seriesIndex])) {
|
||||
$seriesCategory[$seriesIndex]->setScatterLines(false);
|
||||
}
|
||||
if (isset($seriesValues[$seriesIndex])) {
|
||||
$seriesValues[$seriesIndex]->setScatterLines(false);
|
||||
}
|
||||
}
|
||||
if (is_numeric($lineWidth)) {
|
||||
if (isset($seriesLabel[$seriesIndex])) {
|
||||
$seriesLabel[$seriesIndex]->setLineWidth((int) $lineWidth);
|
||||
}
|
||||
if (isset($seriesCategory[$seriesIndex])) {
|
||||
$seriesCategory[$seriesIndex]->setLineWidth((int) $lineWidth);
|
||||
}
|
||||
if (isset($seriesValues[$seriesIndex])) {
|
||||
$seriesValues[$seriesIndex]->setLineWidth((int) $lineWidth);
|
||||
}
|
||||
}
|
||||
if ($schemeClr) {
|
||||
if (isset($seriesLabel[$seriesIndex])) {
|
||||
$seriesLabel[$seriesIndex]->setSchemeClr($schemeClr);
|
||||
}
|
||||
if (isset($seriesCategory[$seriesIndex])) {
|
||||
$seriesCategory[$seriesIndex]->setSchemeClr($schemeClr);
|
||||
}
|
||||
if (isset($seriesValues[$seriesIndex])) {
|
||||
$seriesValues[$seriesIndex]->setSchemeClr($schemeClr);
|
||||
}
|
||||
}
|
||||
if ($bubble3D) {
|
||||
if (isset($seriesLabel[$seriesIndex])) {
|
||||
$seriesLabel[$seriesIndex]->setBubble3D($bubble3D);
|
||||
}
|
||||
if (isset($seriesCategory[$seriesIndex])) {
|
||||
$seriesCategory[$seriesIndex]->setBubble3D($bubble3D);
|
||||
}
|
||||
if (isset($seriesValues[$seriesIndex])) {
|
||||
$seriesValues[$seriesIndex]->setBubble3D($bubble3D);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/** @phpstan-ignore-next-line */
|
||||
$series = new DataSeries($plotType, $multiSeriesType, $plotOrder, $seriesLabel, $seriesCategory, $seriesValues, $smoothLine);
|
||||
$series->setPlotBubbleSizes($seriesBubbles);
|
||||
|
||||
return new DataSeries($plotType, $multiSeriesType, $plotOrder, $seriesLabel, $seriesCategory, $seriesValues, $smoothLine);
|
||||
return $series;
|
||||
}
|
||||
|
||||
private static function chartDataSeriesValueSet($seriesDetail, $namespacesChartMeta, $marker = null)
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
private function chartDataSeriesValueSet(SimpleXMLElement $seriesDetail, ?string $marker = null, ?string $srgbClr = null, ?string $pointSize = null)
|
||||
{
|
||||
if (isset($seriesDetail->strRef)) {
|
||||
$seriesSource = (string) $seriesDetail->strRef->f;
|
||||
$seriesValues = new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, $seriesSource, null, null, null, $marker);
|
||||
$seriesValues = new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, $seriesSource, null, 0, null, $marker, $srgbClr, "$pointSize");
|
||||
|
||||
if (isset($seriesDetail->strRef->strCache)) {
|
||||
$seriesData = self::chartDataSeriesValues($seriesDetail->strRef->strCache->children($namespacesChartMeta['c']), 's');
|
||||
$seriesData = $this->chartDataSeriesValues($seriesDetail->strRef->strCache->children($this->cNamespace), 's');
|
||||
$seriesValues
|
||||
->setFormatCode($seriesData['formatCode'])
|
||||
->setDataValues($seriesData['dataValues']);
|
||||
|
|
@ -356,9 +465,9 @@ class Chart
|
|||
return $seriesValues;
|
||||
} elseif (isset($seriesDetail->numRef)) {
|
||||
$seriesSource = (string) $seriesDetail->numRef->f;
|
||||
$seriesValues = new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, $seriesSource, null, null, null, $marker);
|
||||
$seriesValues = new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, $seriesSource, null, 0, null, $marker, $srgbClr, "$pointSize");
|
||||
if (isset($seriesDetail->numRef->numCache)) {
|
||||
$seriesData = self::chartDataSeriesValues($seriesDetail->numRef->numCache->children($namespacesChartMeta['c']));
|
||||
$seriesData = $this->chartDataSeriesValues($seriesDetail->numRef->numCache->children($this->cNamespace));
|
||||
$seriesValues
|
||||
->setFormatCode($seriesData['formatCode'])
|
||||
->setDataValues($seriesData['dataValues']);
|
||||
|
|
@ -367,10 +476,10 @@ class Chart
|
|||
return $seriesValues;
|
||||
} elseif (isset($seriesDetail->multiLvlStrRef)) {
|
||||
$seriesSource = (string) $seriesDetail->multiLvlStrRef->f;
|
||||
$seriesValues = new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, $seriesSource, null, null, null, $marker);
|
||||
$seriesValues = new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, $seriesSource, null, 0, null, $marker, $srgbClr, "$pointSize");
|
||||
|
||||
if (isset($seriesDetail->multiLvlStrRef->multiLvlStrCache)) {
|
||||
$seriesData = self::chartDataSeriesValuesMultiLevel($seriesDetail->multiLvlStrRef->multiLvlStrCache->children($namespacesChartMeta['c']), 's');
|
||||
$seriesData = $this->chartDataSeriesValuesMultiLevel($seriesDetail->multiLvlStrRef->multiLvlStrCache->children($this->cNamespace), 's');
|
||||
$seriesValues
|
||||
->setFormatCode($seriesData['formatCode'])
|
||||
->setDataValues($seriesData['dataValues']);
|
||||
|
|
@ -379,10 +488,10 @@ class Chart
|
|||
return $seriesValues;
|
||||
} elseif (isset($seriesDetail->multiLvlNumRef)) {
|
||||
$seriesSource = (string) $seriesDetail->multiLvlNumRef->f;
|
||||
$seriesValues = new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, $seriesSource, null, null, null, $marker);
|
||||
$seriesValues = new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, $seriesSource, null, 0, null, $marker, $srgbClr, "$pointSize");
|
||||
|
||||
if (isset($seriesDetail->multiLvlNumRef->multiLvlNumCache)) {
|
||||
$seriesData = self::chartDataSeriesValuesMultiLevel($seriesDetail->multiLvlNumRef->multiLvlNumCache->children($namespacesChartMeta['c']), 's');
|
||||
$seriesData = $this->chartDataSeriesValuesMultiLevel($seriesDetail->multiLvlNumRef->multiLvlNumCache->children($this->cNamespace), 's');
|
||||
$seriesValues
|
||||
->setFormatCode($seriesData['formatCode'])
|
||||
->setDataValues($seriesData['dataValues']);
|
||||
|
|
@ -391,10 +500,20 @@ class Chart
|
|||
return $seriesValues;
|
||||
}
|
||||
|
||||
if (isset($seriesDetail->v)) {
|
||||
return new DataSeriesValues(
|
||||
DataSeriesValues::DATASERIES_TYPE_STRING,
|
||||
null,
|
||||
null,
|
||||
1,
|
||||
[(string) $seriesDetail->v]
|
||||
);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static function chartDataSeriesValues($seriesValueSet, $dataType = 'n')
|
||||
private function chartDataSeriesValues(SimpleXMLElement $seriesValueSet, string $dataType = 'n'): array
|
||||
{
|
||||
$seriesVal = [];
|
||||
$formatCode = '';
|
||||
|
|
@ -414,7 +533,7 @@ class Chart
|
|||
$pointVal = self::getAttribute($seriesValue, 'idx', 'integer');
|
||||
if ($dataType == 's') {
|
||||
$seriesVal[$pointVal] = (string) $seriesValue->v;
|
||||
} elseif ($seriesValue->v === ExcelError::NA()) {
|
||||
} elseif ((string) $seriesValue->v === ExcelError::NA()) {
|
||||
$seriesVal[$pointVal] = null;
|
||||
} else {
|
||||
$seriesVal[$pointVal] = (float) $seriesValue->v;
|
||||
|
|
@ -431,7 +550,7 @@ class Chart
|
|||
];
|
||||
}
|
||||
|
||||
private static function chartDataSeriesValuesMultiLevel($seriesValueSet, $dataType = 'n')
|
||||
private function chartDataSeriesValuesMultiLevel(SimpleXMLElement $seriesValueSet, string $dataType = 'n'): array
|
||||
{
|
||||
$seriesVal = [];
|
||||
$formatCode = '';
|
||||
|
|
@ -452,7 +571,7 @@ class Chart
|
|||
$pointVal = self::getAttribute($seriesValue, 'idx', 'integer');
|
||||
if ($dataType == 's') {
|
||||
$seriesVal[$pointVal][] = (string) $seriesValue->v;
|
||||
} elseif ($seriesValue->v === ExcelError::NA()) {
|
||||
} elseif ((string) $seriesValue->v === ExcelError::NA()) {
|
||||
$seriesVal[$pointVal] = null;
|
||||
} else {
|
||||
$seriesVal[$pointVal][] = (float) $seriesValue->v;
|
||||
|
|
@ -470,74 +589,227 @@ class Chart
|
|||
];
|
||||
}
|
||||
|
||||
private static function parseRichText(SimpleXMLElement $titleDetailPart)
|
||||
private function parseRichText(SimpleXMLElement $titleDetailPart): RichText
|
||||
{
|
||||
$value = new RichText();
|
||||
$objText = null;
|
||||
foreach ($titleDetailPart as $titleDetailElementKey => $titleDetailElement) {
|
||||
if (isset($titleDetailElement->t)) {
|
||||
$objText = $value->createTextRun((string) $titleDetailElement->t);
|
||||
$defaultFontSize = null;
|
||||
$defaultBold = null;
|
||||
$defaultItalic = null;
|
||||
$defaultUnderscore = null;
|
||||
$defaultStrikethrough = null;
|
||||
$defaultBaseline = null;
|
||||
$defaultFontName = null;
|
||||
$defaultLatin = null;
|
||||
$defaultEastAsian = null;
|
||||
$defaultComplexScript = null;
|
||||
$defaultColor = null;
|
||||
if (isset($titleDetailPart->pPr->defRPr)) {
|
||||
/** @var ?int */
|
||||
$defaultFontSize = self::getAttribute($titleDetailPart->pPr->defRPr, 'sz', 'integer');
|
||||
/** @var ?bool */
|
||||
$defaultBold = self::getAttribute($titleDetailPart->pPr->defRPr, 'b', 'boolean');
|
||||
/** @var ?bool */
|
||||
$defaultItalic = self::getAttribute($titleDetailPart->pPr->defRPr, 'i', 'boolean');
|
||||
/** @var ?string */
|
||||
$defaultUnderscore = self::getAttribute($titleDetailPart->pPr->defRPr, 'u', 'string');
|
||||
/** @var ?string */
|
||||
$defaultStrikethrough = self::getAttribute($titleDetailPart->pPr->defRPr, 'strike', 'string');
|
||||
/** @var ?int */
|
||||
$defaultBaseline = self::getAttribute($titleDetailPart->pPr->defRPr, 'baseline', 'integer');
|
||||
if (isset($titleDetailPart->defRPr->rFont['val'])) {
|
||||
$defaultFontName = (string) $titleDetailPart->defRPr->rFont['val'];
|
||||
}
|
||||
if (isset($titleDetailPart->pPr->defRPr->latin)) {
|
||||
/** @var ?string */
|
||||
$defaultLatin = self::getAttribute($titleDetailPart->pPr->defRPr->latin, 'typeface', 'string');
|
||||
}
|
||||
if (isset($titleDetailPart->pPr->defRPr->ea)) {
|
||||
/** @var ?string */
|
||||
$defaultEastAsian = self::getAttribute($titleDetailPart->pPr->defRPr->ea, 'typeface', 'string');
|
||||
}
|
||||
if (isset($titleDetailPart->pPr->defRPr->cs)) {
|
||||
/** @var ?string */
|
||||
$defaultComplexScript = self::getAttribute($titleDetailPart->pPr->defRPr->cs, 'typeface', 'string');
|
||||
}
|
||||
if (isset($titleDetailPart->pPr->defRPr->solidFill->srgbClr)) {
|
||||
/** @var ?string */
|
||||
$defaultColor = self::getAttribute($titleDetailPart->pPr->defRPr->solidFill->srgbClr, 'val', 'string');
|
||||
}
|
||||
}
|
||||
foreach ($titleDetailPart as $titleDetailElementKey => $titleDetailElement) {
|
||||
if (
|
||||
(string) $titleDetailElementKey !== 'r'
|
||||
|| !isset($titleDetailElement->t)
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
$objText = $value->createTextRun((string) $titleDetailElement->t);
|
||||
if ($objText->getFont() === null) {
|
||||
// @codeCoverageIgnoreStart
|
||||
continue;
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
$fontSize = null;
|
||||
$bold = null;
|
||||
$italic = null;
|
||||
$underscore = null;
|
||||
$strikethrough = null;
|
||||
$baseline = null;
|
||||
$fontName = null;
|
||||
$latinName = null;
|
||||
$eastAsian = null;
|
||||
$complexScript = null;
|
||||
$fontColor = null;
|
||||
$uSchemeClr = null;
|
||||
if (isset($titleDetailElement->rPr)) {
|
||||
// not used now, not sure it ever was, grandfathering
|
||||
if (isset($titleDetailElement->rPr->rFont['val'])) {
|
||||
$objText->getFont()->setName((string) $titleDetailElement->rPr->rFont['val']);
|
||||
}
|
||||
|
||||
$fontSize = (self::getAttribute($titleDetailElement->rPr, 'sz', 'integer'));
|
||||
if (is_int($fontSize)) {
|
||||
$objText->getFont()->setSize(floor($fontSize / 100));
|
||||
}
|
||||
|
||||
$fontColor = (self::getAttribute($titleDetailElement->rPr, 'color', 'string'));
|
||||
if ($fontColor !== null) {
|
||||
$objText->getFont()->setColor(new Color(self::readColor($fontColor)));
|
||||
// @codeCoverageIgnoreStart
|
||||
$fontName = (string) $titleDetailElement->rPr->rFont['val'];
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
if (isset($titleDetailElement->rPr->latin)) {
|
||||
/** @var ?string */
|
||||
$latinName = self::getAttribute($titleDetailElement->rPr->latin, 'typeface', 'string');
|
||||
}
|
||||
if (isset($titleDetailElement->rPr->ea)) {
|
||||
/** @var ?string */
|
||||
$eastAsian = self::getAttribute($titleDetailElement->rPr->ea, 'typeface', 'string');
|
||||
}
|
||||
if (isset($titleDetailElement->rPr->cs)) {
|
||||
/** @var ?string */
|
||||
$complexScript = self::getAttribute($titleDetailElement->rPr->cs, 'typeface', 'string');
|
||||
}
|
||||
/** @var ?int */
|
||||
$fontSize = self::getAttribute($titleDetailElement->rPr, 'sz', 'integer');
|
||||
|
||||
// not used now, not sure it ever was, grandfathering
|
||||
/** @var ?string */
|
||||
$fontColor = self::getAttribute($titleDetailElement->rPr, 'color', 'string');
|
||||
if (isset($titleDetailElement->rPr->solidFill->srgbClr)) {
|
||||
/** @var ?string */
|
||||
$fontColor = self::getAttribute($titleDetailElement->rPr->solidFill->srgbClr, 'val', 'string');
|
||||
}
|
||||
|
||||
/** @var ?bool */
|
||||
$bold = self::getAttribute($titleDetailElement->rPr, 'b', 'boolean');
|
||||
if ($bold !== null) {
|
||||
$objText->getFont()->setBold($bold);
|
||||
}
|
||||
|
||||
/** @var ?bool */
|
||||
$italic = self::getAttribute($titleDetailElement->rPr, 'i', 'boolean');
|
||||
if ($italic !== null) {
|
||||
$objText->getFont()->setItalic($italic);
|
||||
}
|
||||
|
||||
/** @var ?int */
|
||||
$baseline = self::getAttribute($titleDetailElement->rPr, 'baseline', 'integer');
|
||||
if ($baseline !== null) {
|
||||
if ($baseline > 0) {
|
||||
$objText->getFont()->setSuperscript(true);
|
||||
} elseif ($baseline < 0) {
|
||||
$objText->getFont()->setSubscript(true);
|
||||
}
|
||||
|
||||
/** @var ?string */
|
||||
$underscore = self::getAttribute($titleDetailElement->rPr, 'u', 'string');
|
||||
if (isset($titleDetailElement->rPr->uFill->solidFill->schemeClr)) {
|
||||
/** @var ?string */
|
||||
$uSchemeClr = self::getAttribute($titleDetailElement->rPr->uFill->solidFill->schemeClr, 'val', 'string');
|
||||
}
|
||||
|
||||
$underscore = (self::getAttribute($titleDetailElement->rPr, 'u', 'string'));
|
||||
if ($underscore !== null) {
|
||||
if ($underscore == 'sng') {
|
||||
$objText->getFont()->setUnderline(Font::UNDERLINE_SINGLE);
|
||||
} elseif ($underscore == 'dbl') {
|
||||
$objText->getFont()->setUnderline(Font::UNDERLINE_DOUBLE);
|
||||
} else {
|
||||
$objText->getFont()->setUnderline(Font::UNDERLINE_NONE);
|
||||
}
|
||||
}
|
||||
/** @var ?string */
|
||||
$strikethrough = self::getAttribute($titleDetailElement->rPr, 'strike', 'string');
|
||||
}
|
||||
|
||||
$strikethrough = (self::getAttribute($titleDetailElement->rPr, 's', 'string'));
|
||||
if ($strikethrough !== null) {
|
||||
if ($strikethrough == 'noStrike') {
|
||||
$objText->getFont()->setStrikethrough(false);
|
||||
} else {
|
||||
$objText->getFont()->setStrikethrough(true);
|
||||
}
|
||||
$fontFound = false;
|
||||
$latinName = $latinName ?? $defaultLatin;
|
||||
if ($latinName !== null) {
|
||||
$objText->getFont()->setLatin($latinName);
|
||||
$fontFound = true;
|
||||
}
|
||||
$eastAsian = $eastAsian ?? $defaultEastAsian;
|
||||
if ($eastAsian !== null) {
|
||||
$objText->getFont()->setEastAsian($eastAsian);
|
||||
$fontFound = true;
|
||||
}
|
||||
$complexScript = $complexScript ?? $defaultComplexScript;
|
||||
if ($complexScript !== null) {
|
||||
$objText->getFont()->setComplexScript($complexScript);
|
||||
$fontFound = true;
|
||||
}
|
||||
$fontName = $fontName ?? $defaultFontName;
|
||||
if ($fontName !== null) {
|
||||
// @codeCoverageIgnoreStart
|
||||
$objText->getFont()->setName($fontName);
|
||||
$fontFound = true;
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
|
||||
$fontSize = $fontSize ?? $defaultFontSize;
|
||||
if (is_int($fontSize)) {
|
||||
$objText->getFont()->setSize(floor($fontSize / 100));
|
||||
$fontFound = true;
|
||||
}
|
||||
|
||||
$fontColor = $fontColor ?? $defaultColor;
|
||||
if ($fontColor !== null) {
|
||||
$objText->getFont()->setColor(new Color($fontColor));
|
||||
$fontFound = true;
|
||||
}
|
||||
|
||||
$bold = $bold ?? $defaultBold;
|
||||
if ($bold !== null) {
|
||||
$objText->getFont()->setBold($bold);
|
||||
$fontFound = true;
|
||||
}
|
||||
|
||||
$italic = $italic ?? $defaultItalic;
|
||||
if ($italic !== null) {
|
||||
$objText->getFont()->setItalic($italic);
|
||||
$fontFound = true;
|
||||
}
|
||||
|
||||
$baseline = $baseline ?? $defaultBaseline;
|
||||
if ($baseline !== null) {
|
||||
$objText->getFont()->setBaseLine($baseline);
|
||||
if ($baseline > 0) {
|
||||
$objText->getFont()->setSuperscript(true);
|
||||
} elseif ($baseline < 0) {
|
||||
$objText->getFont()->setSubscript(true);
|
||||
}
|
||||
$fontFound = true;
|
||||
}
|
||||
|
||||
$underscore = $underscore ?? $defaultUnderscore;
|
||||
if ($underscore !== null) {
|
||||
if ($underscore == 'sng') {
|
||||
$objText->getFont()->setUnderline(Font::UNDERLINE_SINGLE);
|
||||
} elseif ($underscore == 'dbl') {
|
||||
$objText->getFont()->setUnderline(Font::UNDERLINE_DOUBLE);
|
||||
} elseif ($underscore !== '') {
|
||||
$objText->getFont()->setUnderline($underscore);
|
||||
} else {
|
||||
$objText->getFont()->setUnderline(Font::UNDERLINE_NONE);
|
||||
}
|
||||
$fontFound = true;
|
||||
if ($uSchemeClr) {
|
||||
$objText->getFont()->setUSchemeClr($uSchemeClr);
|
||||
}
|
||||
}
|
||||
|
||||
$strikethrough = $strikethrough ?? $defaultStrikethrough;
|
||||
if ($strikethrough !== null) {
|
||||
$objText->getFont()->setStrikeType($strikethrough);
|
||||
if ($strikethrough == 'noStrike') {
|
||||
$objText->getFont()->setStrikethrough(false);
|
||||
} else {
|
||||
$objText->getFont()->setStrikethrough(true);
|
||||
}
|
||||
$fontFound = true;
|
||||
}
|
||||
if ($fontFound === false) {
|
||||
$objText->setFont(null);
|
||||
}
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
private static function readChartAttributes($chartDetail)
|
||||
/**
|
||||
* @param null|Layout|SimpleXMLElement $chartDetail
|
||||
*/
|
||||
private function readChartAttributes($chartDetail): array
|
||||
{
|
||||
$plotAttributes = [];
|
||||
if (isset($chartDetail->dLbls)) {
|
||||
|
|
@ -570,7 +842,7 @@ class Chart
|
|||
/**
|
||||
* @param mixed $plotAttributes
|
||||
*/
|
||||
private static function setChartAttributes(Layout $plotArea, $plotAttributes): void
|
||||
private function setChartAttributes(Layout $plotArea, $plotAttributes): void
|
||||
{
|
||||
foreach ($plotAttributes as $plotAttributeKey => $plotAttributeValue) {
|
||||
switch ($plotAttributeKey) {
|
||||
|
|
|
|||
|
|
@ -50,6 +50,8 @@ class Namespaces
|
|||
|
||||
const WORKSHEET = 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet';
|
||||
|
||||
const CHARTSHEET = 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/chartsheet';
|
||||
|
||||
const SCHEMA_MICROSOFT = 'http://schemas.microsoft.com/office/2006/relationships';
|
||||
|
||||
const EXTENSIBILITY = 'http://schemas.microsoft.com/office/2006/relationships/ui/extensibility';
|
||||
|
|
@ -74,5 +76,7 @@ class Namespaces
|
|||
|
||||
const PURL_DRAWING = 'http://purl.oclc.org/ooxml/drawingml/main';
|
||||
|
||||
const PURL_CHART = 'http://purl.oclc.org/ooxml/drawingml/chart';
|
||||
|
||||
const PURL_WORKSHEET = 'http://purl.oclc.org/ooxml/officeDocument/relationships/worksheet';
|
||||
}
|
||||
|
|
|
|||
|
|
@ -90,9 +90,9 @@ class Xml extends BaseReader
|
|||
// Retrieve charset encoding
|
||||
if (preg_match('/<?xml.*encoding=[\'"](.*?)[\'"].*?>/m', $data, $matches)) {
|
||||
$charSet = strtoupper($matches[1]);
|
||||
if (1 == preg_match('/^ISO-8859-\d[\dL]?$/i', $charSet)) {
|
||||
if (preg_match('/^ISO-8859-\d[\dL]?$/i', $charSet) === 1) {
|
||||
$data = StringHelper::convertEncoding($data, 'UTF-8', $charSet);
|
||||
$data = preg_replace('/(<?xml.*encoding=[\'"]).*?([\'"].*?>)/um', '$1' . 'UTF-8' . '$2', $data, 1);
|
||||
$data = (string) preg_replace('/(<?xml.*encoding=[\'"]).*?([\'"].*?>)/um', '$1' . 'UTF-8' . '$2', $data, 1);
|
||||
}
|
||||
}
|
||||
$this->fileContents = $data;
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ class Properties
|
|||
|
||||
foreach ($xml->CustomDocumentProperties[0] as $propertyName => $propertyValue) {
|
||||
$propertyAttributes = self::getAttributes($propertyValue, $namespaces['dt']);
|
||||
$propertyName = preg_replace_callback('/_x([0-9a-f]{4})_/i', [$this, 'hex2str'], $propertyName);
|
||||
$propertyName = (string) preg_replace_callback('/_x([0-9a-f]{4})_/i', [$this, 'hex2str'], $propertyName);
|
||||
|
||||
$this->processCustomProperty($docProps, $propertyName, $propertyValue, $propertyAttributes);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -687,7 +687,7 @@ class ReferenceHelper
|
|||
ksort($cellTokens);
|
||||
ksort($newCellTokens);
|
||||
} // Update cell references in the formula
|
||||
$formulaBlock = str_replace('\\', '', preg_replace($cellTokens, $newCellTokens, $formulaBlock));
|
||||
$formulaBlock = str_replace('\\', '', (string) preg_replace($cellTokens, $newCellTokens, $formulaBlock));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -219,7 +219,7 @@ class CellMatcher
|
|||
foreach ($splitCondition as &$value) {
|
||||
// Only count/replace in alternating array entries (ie. not in quoted strings)
|
||||
if ($i = !$i) {
|
||||
$value = preg_replace_callback(
|
||||
$value = (string) preg_replace_callback(
|
||||
'/' . Calculation::CALCULATION_REGEXP_CELLREF_RELATIVE . '/i',
|
||||
[$this, 'conditionCellAdjustment'],
|
||||
$value
|
||||
|
|
@ -287,7 +287,7 @@ class CellMatcher
|
|||
$conditions = $this->adjustConditionsForCellReferences($conditional->getConditions());
|
||||
$expression = array_pop($conditions);
|
||||
|
||||
$expression = preg_replace(
|
||||
$expression = (string) preg_replace(
|
||||
'/\b' . $this->referenceCell . '\b/i',
|
||||
(string) $this->wrapCellValue(),
|
||||
$expression
|
||||
|
|
|
|||
|
|
@ -133,7 +133,7 @@ abstract class WizardAbstract
|
|||
foreach ($splitCondition as &$value) {
|
||||
// Only count/replace in alternating array entries (ie. not in quoted strings)
|
||||
if ($i = !$i) {
|
||||
$value = preg_replace_callback(
|
||||
$value = (string) preg_replace_callback(
|
||||
'/' . Calculation::CALCULATION_REGEXP_CELLREF_RELATIVE . '/i',
|
||||
function ($matches) use ($referenceColumnIndex, $referenceRow) {
|
||||
return self::reverseCellAdjustment($matches, $referenceColumnIndex, $referenceRow);
|
||||
|
|
@ -174,7 +174,7 @@ abstract class WizardAbstract
|
|||
foreach ($splitCondition as &$value) {
|
||||
// Only count/replace in alternating array entries (ie. not in quoted strings)
|
||||
if ($i = !$i) {
|
||||
$value = preg_replace_callback(
|
||||
$value = (string) preg_replace_callback(
|
||||
'/' . Calculation::CALCULATION_REGEXP_CELLREF_RELATIVE . '/i',
|
||||
[$this, 'conditionCellAdjustment'],
|
||||
$value
|
||||
|
|
|
|||
|
|
@ -18,6 +18,29 @@ class Font extends Supervisor
|
|||
*/
|
||||
protected $name = 'Calibri';
|
||||
|
||||
/**
|
||||
* The following 6 are used only for chart titles, I think.
|
||||
*
|
||||
*@var string
|
||||
*/
|
||||
private $latin = '';
|
||||
|
||||
/** @var string */
|
||||
private $eastAsian = '';
|
||||
|
||||
/** @var string */
|
||||
private $complexScript = '';
|
||||
|
||||
/** @var int */
|
||||
private $baseLine = 0;
|
||||
|
||||
/** @var string */
|
||||
private $strikeType = '';
|
||||
|
||||
/** @var string */
|
||||
private $uSchemeClr = '';
|
||||
// end of chart title items
|
||||
|
||||
/**
|
||||
* Font Size.
|
||||
*
|
||||
|
|
@ -170,6 +193,15 @@ class Font extends Supervisor
|
|||
if (isset($styleArray['name'])) {
|
||||
$this->setName($styleArray['name']);
|
||||
}
|
||||
if (isset($styleArray['latin'])) {
|
||||
$this->setLatin($styleArray['latin']);
|
||||
}
|
||||
if (isset($styleArray['eastAsian'])) {
|
||||
$this->setEastAsian($styleArray['eastAsian']);
|
||||
}
|
||||
if (isset($styleArray['complexScript'])) {
|
||||
$this->setComplexScript($styleArray['complexScript']);
|
||||
}
|
||||
if (isset($styleArray['bold'])) {
|
||||
$this->setBold($styleArray['bold']);
|
||||
}
|
||||
|
|
@ -213,6 +245,33 @@ class Font extends Supervisor
|
|||
return $this->name;
|
||||
}
|
||||
|
||||
public function getLatin(): string
|
||||
{
|
||||
if ($this->isSupervisor) {
|
||||
return $this->getSharedComponent()->getLatin();
|
||||
}
|
||||
|
||||
return $this->latin;
|
||||
}
|
||||
|
||||
public function getEastAsian(): string
|
||||
{
|
||||
if ($this->isSupervisor) {
|
||||
return $this->getSharedComponent()->getEastAsian();
|
||||
}
|
||||
|
||||
return $this->eastAsian;
|
||||
}
|
||||
|
||||
public function getComplexScript(): string
|
||||
{
|
||||
if ($this->isSupervisor) {
|
||||
return $this->getSharedComponent()->getComplexScript();
|
||||
}
|
||||
|
||||
return $this->complexScript;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set Name.
|
||||
*
|
||||
|
|
@ -235,6 +294,51 @@ class Font extends Supervisor
|
|||
return $this;
|
||||
}
|
||||
|
||||
public function setLatin(string $fontname): self
|
||||
{
|
||||
if ($fontname == '') {
|
||||
$fontname = 'Calibri';
|
||||
}
|
||||
if ($this->isSupervisor) {
|
||||
$styleArray = $this->getStyleArray(['latin' => $fontname]);
|
||||
$this->getActiveSheet()->getStyle($this->getSelectedCells())->applyFromArray($styleArray);
|
||||
} else {
|
||||
$this->latin = $fontname;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setEastAsian(string $fontname): self
|
||||
{
|
||||
if ($fontname == '') {
|
||||
$fontname = 'Calibri';
|
||||
}
|
||||
if ($this->isSupervisor) {
|
||||
$styleArray = $this->getStyleArray(['eastAsian' => $fontname]);
|
||||
$this->getActiveSheet()->getStyle($this->getSelectedCells())->applyFromArray($styleArray);
|
||||
} else {
|
||||
$this->eastAsian = $fontname;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setComplexScript(string $fontname): self
|
||||
{
|
||||
if ($fontname == '') {
|
||||
$fontname = 'Calibri';
|
||||
}
|
||||
if ($this->isSupervisor) {
|
||||
$styleArray = $this->getStyleArray(['complexScript' => $fontname]);
|
||||
$this->getActiveSheet()->getStyle($this->getSelectedCells())->applyFromArray($styleArray);
|
||||
} else {
|
||||
$this->complexScript = $fontname;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Size.
|
||||
*
|
||||
|
|
@ -418,6 +522,69 @@ class Font extends Supervisor
|
|||
return $this;
|
||||
}
|
||||
|
||||
public function getBaseLine(): int
|
||||
{
|
||||
if ($this->isSupervisor) {
|
||||
return $this->getSharedComponent()->getBaseLine();
|
||||
}
|
||||
|
||||
return $this->baseLine;
|
||||
}
|
||||
|
||||
public function setBaseLine(int $baseLine): self
|
||||
{
|
||||
if ($this->isSupervisor) {
|
||||
$styleArray = $this->getStyleArray(['baseLine' => $baseLine]);
|
||||
$this->getActiveSheet()->getStyle($this->getSelectedCells())->applyFromArray($styleArray);
|
||||
} else {
|
||||
$this->baseLine = $baseLine;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getStrikeType(): string
|
||||
{
|
||||
if ($this->isSupervisor) {
|
||||
return $this->getSharedComponent()->getStrikeType();
|
||||
}
|
||||
|
||||
return $this->strikeType;
|
||||
}
|
||||
|
||||
public function setStrikeType(string $strikeType): self
|
||||
{
|
||||
if ($this->isSupervisor) {
|
||||
$styleArray = $this->getStyleArray(['strikeType' => $strikeType]);
|
||||
$this->getActiveSheet()->getStyle($this->getSelectedCells())->applyFromArray($styleArray);
|
||||
} else {
|
||||
$this->strikeType = $strikeType;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getUSchemeClr(): string
|
||||
{
|
||||
if ($this->isSupervisor) {
|
||||
return $this->getSharedComponent()->getUSchemeClr();
|
||||
}
|
||||
|
||||
return $this->uSchemeClr;
|
||||
}
|
||||
|
||||
public function setUSchemeClr(string $uSchemeClr): self
|
||||
{
|
||||
if ($this->isSupervisor) {
|
||||
$styleArray = $this->getStyleArray(['uSchemeClr' => $uSchemeClr]);
|
||||
$this->getActiveSheet()->getStyle($this->getSelectedCells())->applyFromArray($styleArray);
|
||||
} else {
|
||||
$this->uSchemeClr = $uSchemeClr;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Underline.
|
||||
*
|
||||
|
|
@ -546,6 +713,15 @@ class Font extends Supervisor
|
|||
$this->underline .
|
||||
($this->strikethrough ? 't' : 'f') .
|
||||
$this->color->getHashCode() .
|
||||
'*' .
|
||||
$this->latin .
|
||||
'*' .
|
||||
$this->eastAsian .
|
||||
'*' .
|
||||
$this->complexScript .
|
||||
$this->strikeType .
|
||||
$this->uSchemeClr .
|
||||
(string) $this->baseLine .
|
||||
__CLASS__
|
||||
);
|
||||
}
|
||||
|
|
@ -553,12 +729,17 @@ class Font extends Supervisor
|
|||
protected function exportArray1(): array
|
||||
{
|
||||
$exportedArray = [];
|
||||
$this->exportArray2($exportedArray, 'baseLine', $this->getBaseLine());
|
||||
$this->exportArray2($exportedArray, 'bold', $this->getBold());
|
||||
$this->exportArray2($exportedArray, 'color', $this->getColor());
|
||||
$this->exportArray2($exportedArray, 'complexScript', $this->getComplexScript());
|
||||
$this->exportArray2($exportedArray, 'eastAsian', $this->getEastAsian());
|
||||
$this->exportArray2($exportedArray, 'italic', $this->getItalic());
|
||||
$this->exportArray2($exportedArray, 'latin', $this->getLatin());
|
||||
$this->exportArray2($exportedArray, 'name', $this->getName());
|
||||
$this->exportArray2($exportedArray, 'size', $this->getSize());
|
||||
$this->exportArray2($exportedArray, 'strikethrough', $this->getStrikethrough());
|
||||
$this->exportArray2($exportedArray, 'strikeType', $this->getStrikeType());
|
||||
$this->exportArray2($exportedArray, 'subscript', $this->getSubscript());
|
||||
$this->exportArray2($exportedArray, 'superscript', $this->getSuperscript());
|
||||
$this->exportArray2($exportedArray, 'underline', $this->getUnderline());
|
||||
|
|
|
|||
|
|
@ -129,11 +129,10 @@ class DateFormatter
|
|||
// but we don't want to change any quoted strings
|
||||
/** @var callable */
|
||||
$callable = [self::class, 'setLowercaseCallback'];
|
||||
$format = preg_replace_callback('/(?:^|")([^"]*)(?:$|")/', $callable, $format);
|
||||
$format = (string) preg_replace_callback('/(?:^|")([^"]*)(?:$|")/', $callable, $format);
|
||||
|
||||
// Only process the non-quoted blocks for date format characters
|
||||
|
||||
/** @phpstan-ignore-next-line */
|
||||
$blocks = explode('"', $format);
|
||||
foreach ($blocks as $key => &$block) {
|
||||
if ($key % 2 == 0) {
|
||||
|
|
|
|||
|
|
@ -51,12 +51,12 @@ class Formatter
|
|||
for ($idx = 0; $idx < $cnt; ++$idx) {
|
||||
if (preg_match($color_regex, $sections[$idx], $matches)) {
|
||||
$colors[$idx] = $matches[0];
|
||||
$sections[$idx] = preg_replace($color_regex, '', $sections[$idx]);
|
||||
$sections[$idx] = (string) preg_replace($color_regex, '', $sections[$idx]);
|
||||
}
|
||||
if (preg_match($cond_regex, $sections[$idx], $matches)) {
|
||||
$condops[$idx] = $matches[1];
|
||||
$condvals[$idx] = $matches[2];
|
||||
$sections[$idx] = preg_replace($cond_regex, '', $sections[$idx]);
|
||||
$sections[$idx] = (string) preg_replace($cond_regex, '', $sections[$idx]);
|
||||
}
|
||||
}
|
||||
$color = $colors[0];
|
||||
|
|
@ -112,7 +112,7 @@ class Formatter
|
|||
return $value;
|
||||
}
|
||||
|
||||
$format = preg_replace_callback(
|
||||
$format = (string) preg_replace_callback(
|
||||
'/(["])(?:(?=(\\\\?))\\2.)*?\\1/u',
|
||||
function ($matches) {
|
||||
return str_replace('.', chr(0x00), $matches[0]);
|
||||
|
|
@ -121,7 +121,7 @@ class Formatter
|
|||
);
|
||||
|
||||
// Convert any other escaped characters to quoted strings, e.g. (\T to "T")
|
||||
$format = preg_replace('/(\\\(((.)(?!((AM\/PM)|(A\/P))))|([^ ])))(?=(?:[^"]|"[^"]*")*$)/ui', '"${2}"', $format);
|
||||
$format = (string) preg_replace('/(\\\(((.)(?!((AM\/PM)|(A\/P))))|([^ ])))(?=(?:[^"]|"[^"]*")*$)/ui', '"${2}"', $format);
|
||||
|
||||
// Get the sections, there can be up to four sections, separated with a semi-colon (but only if not a quoted literal)
|
||||
$sections = preg_split('/(;)(?=(?:[^"]|"[^"]*")*$)/u', $format);
|
||||
|
|
@ -130,7 +130,7 @@ class Formatter
|
|||
|
||||
// In Excel formats, "_" is used to add spacing,
|
||||
// The following character indicates the size of the spacing, which we can't do in HTML, so we just use a standard space
|
||||
$format = preg_replace('/_.?/ui', ' ', $format);
|
||||
$format = (string) preg_replace('/_.?/ui', ' ', $format);
|
||||
|
||||
// Let's begin inspecting the format and converting the value to a formatted string
|
||||
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ class PercentageFormatter extends BaseFormatter
|
|||
|
||||
$wholePartSize += $decimalPartSize;
|
||||
$replacement = "{$wholePartSize}.{$decimalPartSize}";
|
||||
$mask = preg_replace('/[#0,]+\.?[?#0,]*/ui', "%{$replacement}f{$placeHolders}", $format);
|
||||
$mask = (string) preg_replace('/[#0,]+\.?[?#0,]*/ui', "%{$replacement}f{$placeHolders}", $format);
|
||||
|
||||
/** @var float */
|
||||
$valueFloat = $value;
|
||||
|
|
|
|||
|
|
@ -145,7 +145,7 @@ class AutoFilter
|
|||
$this->evaluated = false;
|
||||
if ($this->workSheet !== null) {
|
||||
$thisrange = $this->range;
|
||||
$range = preg_replace('/\\d+$/', (string) $this->workSheet->getHighestRow(), $thisrange) ?? '';
|
||||
$range = (string) preg_replace('/\\d+$/', (string) $this->workSheet->getHighestRow(), $thisrange);
|
||||
if ($range !== $thisrange) {
|
||||
$this->setRange($range);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -212,7 +212,7 @@ class Table
|
|||
{
|
||||
if ($this->workSheet !== null) {
|
||||
$thisrange = $this->range;
|
||||
$range = preg_replace('/\\d+$/', (string) $this->workSheet->getHighestRow(), $thisrange) ?? '';
|
||||
$range = (string) preg_replace('/\\d+$/', (string) $this->workSheet->getHighestRow(), $thisrange);
|
||||
if ($range !== $thisrange) {
|
||||
$this->setRange($range);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -42,10 +42,9 @@ class Validations
|
|||
public static function validateCellOrCellRange($cellRange): string
|
||||
{
|
||||
if (is_string($cellRange) || is_numeric($cellRange)) {
|
||||
// Convert a single column reference like 'A' to 'A:A'
|
||||
$cellRange = (string) preg_replace('/^([A-Z]+)$/', '${1}:${1}', (string) $cellRange);
|
||||
// Convert a single row reference like '1' to '1:1'
|
||||
$cellRange = (string) preg_replace('/^(\d+)$/', '${1}:${1}', $cellRange);
|
||||
// Convert a single column reference like 'A' to 'A:A',
|
||||
// a single row reference like '1' to '1:1'
|
||||
$cellRange = (string) preg_replace('/^([A-Z]+|\d+)$/', '${1}:${1}', (string) $cellRange);
|
||||
} elseif (is_object($cellRange) && $cellRange instanceof CellAddress) {
|
||||
$cellRange = new CellRange($cellRange, $cellRange);
|
||||
}
|
||||
|
|
@ -66,9 +65,12 @@ class Validations
|
|||
[$worksheet, $addressRange] = Worksheet::extractSheetTitle($cellRange, true);
|
||||
|
||||
// Convert Column ranges like 'A:C' to 'A1:C1048576'
|
||||
$addressRange = (string) preg_replace('/^([A-Z]+):([A-Z]+)$/', '${1}1:${2}1048576', $addressRange);
|
||||
// Convert Row ranges like '1:3' to 'A1:XFD3'
|
||||
$addressRange = (string) preg_replace('/^(\\d+):(\\d+)$/', 'A${1}:XFD${2}', $addressRange);
|
||||
// or Row ranges like '1:3' to 'A1:XFD3'
|
||||
$addressRange = (string) preg_replace(
|
||||
['/^([A-Z]+):([A-Z]+)$/i', '/^(\\d+):(\\d+)$/'],
|
||||
['${1}1:${2}1048576', 'A${1}:XFD${2}'],
|
||||
$addressRange
|
||||
);
|
||||
|
||||
return empty($worksheet) ? strtoupper($addressRange) : $worksheet . '!' . strtoupper($addressRange);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -662,13 +662,13 @@ class Html extends BaseWriter
|
|||
$filename = $drawing->getPath();
|
||||
|
||||
// Strip off eventual '.'
|
||||
$filename = preg_replace('/^[.]/', '', $filename);
|
||||
$filename = (string) preg_replace('/^[.]/', '', $filename);
|
||||
|
||||
// Prepend images root
|
||||
$filename = $this->getImagesRoot() . $filename;
|
||||
|
||||
// Strip off eventual '.' if followed by non-/
|
||||
$filename = preg_replace('@^[.]([^/])@', '$1', $filename);
|
||||
$filename = (string) preg_replace('@^[.]([^/])@', '$1', $filename);
|
||||
|
||||
// Convert UTF8 data to PCDATA
|
||||
$filename = htmlspecialchars($filename, Settings::htmlEntityFlags());
|
||||
|
|
@ -1326,7 +1326,7 @@ class Html extends BaseWriter
|
|||
|
||||
// Converts the cell content so that spaces occuring at beginning of each new line are replaced by
|
||||
// Example: " Hello\n to the world" is converted to " Hello\n to the world"
|
||||
$cellData = preg_replace('/(?m)(?:^|\\G) /', ' ', $cellData);
|
||||
$cellData = (string) preg_replace('/(?m)(?:^|\\G) /', ' ', $cellData);
|
||||
|
||||
// convert newline "\n" to '<br>'
|
||||
$cellData = nl2br($cellData);
|
||||
|
|
|
|||
|
|
@ -10,12 +10,14 @@ use PhpOffice\PhpSpreadsheet\Style\Font;
|
|||
use PhpOffice\PhpSpreadsheet\Style\Style as CellStyle;
|
||||
use PhpOffice\PhpSpreadsheet\Worksheet\ColumnDimension;
|
||||
use PhpOffice\PhpSpreadsheet\Worksheet\RowDimension;
|
||||
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
|
||||
|
||||
class Style
|
||||
{
|
||||
public const CELL_STYLE_PREFIX = 'ce';
|
||||
public const COLUMN_STYLE_PREFIX = 'co';
|
||||
public const ROW_STYLE_PREFIX = 'ro';
|
||||
public const TABLE_STYLE_PREFIX = 'ta';
|
||||
|
||||
private $writer;
|
||||
|
||||
|
|
@ -221,6 +223,26 @@ class Style
|
|||
$this->writer->endElement(); // Close style:style
|
||||
}
|
||||
|
||||
public function writeTableStyle(Worksheet $worksheet, int $sheetId): void
|
||||
{
|
||||
$this->writer->startElement('style:style');
|
||||
$this->writer->writeAttribute('style:family', 'table');
|
||||
$this->writer->writeAttribute(
|
||||
'style:name',
|
||||
sprintf('%s%d', self::TABLE_STYLE_PREFIX, $sheetId)
|
||||
);
|
||||
|
||||
$this->writer->startElement('style:table-properties');
|
||||
|
||||
$this->writer->writeAttribute(
|
||||
'table:display',
|
||||
$worksheet->getSheetState() === Worksheet::SHEETSTATE_VISIBLE ? 'true' : 'false'
|
||||
);
|
||||
|
||||
$this->writer->endElement(); // Close style:table-properties
|
||||
$this->writer->endElement(); // Close style:style
|
||||
}
|
||||
|
||||
public function write(CellStyle $style): void
|
||||
{
|
||||
$this->writer->startElement('style:style');
|
||||
|
|
|
|||
|
|
@ -123,6 +123,7 @@ class Content extends WriterPart
|
|||
for ($sheetIndex = 0; $sheetIndex < $sheetCount; ++$sheetIndex) {
|
||||
$objWriter->startElement('table:table');
|
||||
$objWriter->writeAttribute('table:name', $spreadsheet->getSheet($sheetIndex)->getTitle());
|
||||
$objWriter->writeAttribute('table:style-name', Style::TABLE_STYLE_PREFIX . (string) ($sheetIndex + 1));
|
||||
$objWriter->writeElement('office:forms');
|
||||
foreach ($spreadsheet->getSheet($sheetIndex)->getColumnDimensions() as $columnDimension) {
|
||||
$objWriter->startElement('table:table-column');
|
||||
|
|
@ -289,6 +290,8 @@ class Content extends WriterPart
|
|||
$sheetCount = $spreadsheet->getSheetCount();
|
||||
for ($i = 0; $i < $sheetCount; ++$i) {
|
||||
$worksheet = $spreadsheet->getSheet($i);
|
||||
$styleWriter->writeTableStyle($worksheet, $i + 1);
|
||||
|
||||
$worksheet->calculateColumnWidths();
|
||||
foreach ($worksheet->getColumnDimensions() as $columnDimension) {
|
||||
if ($columnDimension->getWidth() !== -1.0) {
|
||||
|
|
|
|||
|
|
@ -778,8 +778,7 @@ class Parser
|
|||
*/
|
||||
private function getRefIndex($ext_ref)
|
||||
{
|
||||
$ext_ref = preg_replace("/^'/", '', $ext_ref); // Remove leading ' if any.
|
||||
$ext_ref = preg_replace("/'$/", '', $ext_ref); // Remove trailing ' if any.
|
||||
$ext_ref = (string) preg_replace(["/^'/", "/'$/"], ['', ''], $ext_ref); // Remove leading and trailing ' if any.
|
||||
$ext_ref = str_replace('\'\'', '\'', $ext_ref); // Replace escaped '' with '
|
||||
|
||||
// Check if there is a sheet range eg., Sheet1:Sheet2.
|
||||
|
|
|
|||
|
|
@ -1039,7 +1039,7 @@ class Worksheet extends BIFFwriter
|
|||
$record = 0x01B8; // Record identifier
|
||||
|
||||
// Strip URL type
|
||||
$url = preg_replace('/^internal:/', '', $url);
|
||||
$url = (string) preg_replace('/^internal:/', '', $url);
|
||||
|
||||
// Pack the undocumented parts of the hyperlink stream
|
||||
$unknown1 = pack('H*', 'D0C9EA79F9BACE118C8200AA004BA90B02000000');
|
||||
|
|
@ -1095,8 +1095,7 @@ class Worksheet extends BIFFwriter
|
|||
|
||||
// Strip URL type and change Unix dir separator to Dos style (if needed)
|
||||
//
|
||||
$url = preg_replace('/^external:/', '', $url);
|
||||
$url = preg_replace('/\//', '\\', $url);
|
||||
$url = (string) preg_replace(['/^external:/', '/\//'], ['', '\\'], $url);
|
||||
|
||||
// Determine if the link is relative or absolute:
|
||||
// relative if link contains no dir separator, "somefile.xls"
|
||||
|
|
@ -1125,7 +1124,7 @@ class Worksheet extends BIFFwriter
|
|||
$up_count = pack('v', $up_count);
|
||||
|
||||
// Store the short dos dir name (null terminated)
|
||||
$dir_short = preg_replace('/\\.\\.\\\\/', '', $dir_long) . "\0";
|
||||
$dir_short = (string) preg_replace('/\\.\\.\\\\/', '', $dir_long) . "\0";
|
||||
|
||||
// Store the long dir name as a wchar string (non-null terminated)
|
||||
$dir_long = $dir_long . "\0";
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@ use PhpOffice\PhpSpreadsheet\Chart\Layout;
|
|||
use PhpOffice\PhpSpreadsheet\Chart\Legend;
|
||||
use PhpOffice\PhpSpreadsheet\Chart\PlotArea;
|
||||
use PhpOffice\PhpSpreadsheet\Chart\Title;
|
||||
use PhpOffice\PhpSpreadsheet\Shared\StringHelper;
|
||||
use PhpOffice\PhpSpreadsheet\Shared\XMLWriter;
|
||||
use PhpOffice\PhpSpreadsheet\Writer\Exception as WriterException;
|
||||
|
||||
|
|
@ -75,6 +74,33 @@ class Chart extends WriterPart
|
|||
$objWriter->writeAttribute('val', 0);
|
||||
$objWriter->endElement();
|
||||
|
||||
$objWriter->startElement('c:view3D');
|
||||
$rotX = $chart->getRotX();
|
||||
if (is_int($rotX)) {
|
||||
$objWriter->startElement('c:rotX');
|
||||
$objWriter->writeAttribute('val', "$rotX");
|
||||
$objWriter->endElement();
|
||||
}
|
||||
$rotY = $chart->getRotY();
|
||||
if (is_int($rotY)) {
|
||||
$objWriter->startElement('c:rotY');
|
||||
$objWriter->writeAttribute('val', "$rotY");
|
||||
$objWriter->endElement();
|
||||
}
|
||||
$rAngAx = $chart->getRAngAx();
|
||||
if (is_int($rAngAx)) {
|
||||
$objWriter->startElement('c:rAngAx');
|
||||
$objWriter->writeAttribute('val', "$rAngAx");
|
||||
$objWriter->endElement();
|
||||
}
|
||||
$perspective = $chart->getPerspective();
|
||||
if (is_int($perspective)) {
|
||||
$objWriter->startElement('c:perspective');
|
||||
$objWriter->writeAttribute('val', "$perspective");
|
||||
$objWriter->endElement();
|
||||
}
|
||||
$objWriter->endElement(); // view3D
|
||||
|
||||
$this->writePlotArea($objWriter, $chart->getPlotArea(), $chart->getXAxisLabel(), $chart->getYAxisLabel(), $chart->getChartAxisX(), $chart->getChartAxisY(), $chart->getMajorGridlines(), $chart->getMinorGridlines());
|
||||
|
||||
$this->writeLegend($objWriter, $chart->getLegend());
|
||||
|
|
@ -121,6 +147,10 @@ class Chart extends WriterPart
|
|||
$objWriter->endElement();
|
||||
|
||||
$objWriter->startElement('a:p');
|
||||
$objWriter->startElement('a:pPr');
|
||||
$objWriter->startElement('a:defRPr');
|
||||
$objWriter->endElement();
|
||||
$objWriter->endElement();
|
||||
|
||||
$caption = $title->getCaption();
|
||||
if ((is_array($caption)) && (count($caption) > 0)) {
|
||||
|
|
@ -196,7 +226,7 @@ class Chart extends WriterPart
|
|||
return;
|
||||
}
|
||||
|
||||
$id1 = $id2 = 0;
|
||||
$id1 = $id2 = $id3 = '0';
|
||||
$this->seriesIndex = 0;
|
||||
$objWriter->startElement('c:plotArea');
|
||||
|
||||
|
|
@ -226,6 +256,10 @@ class Chart extends WriterPart
|
|||
$objWriter->startElement('c:scatterStyle');
|
||||
$objWriter->writeAttribute('val', $plotStyle);
|
||||
$objWriter->endElement();
|
||||
} elseif ($groupType === DataSeries::TYPE_SURFACECHART_3D || $groupType === DataSeries::TYPE_SURFACECHART) {
|
||||
$objWriter->startElement('c:wireframe');
|
||||
$objWriter->writeAttribute('val', $plotStyle ? '1' : '0');
|
||||
$objWriter->endElement();
|
||||
}
|
||||
|
||||
$this->writePlotGroup($plotGroup, $chartType, $objWriter, $catIsMultiLevelSeries, $valIsMultiLevelSeries, $plotGroupingType);
|
||||
|
|
@ -250,9 +284,12 @@ class Chart extends WriterPart
|
|||
$objWriter->endElement();
|
||||
}
|
||||
} elseif ($chartType === DataSeries::TYPE_BUBBLECHART) {
|
||||
$objWriter->startElement('c:bubbleScale');
|
||||
$objWriter->writeAttribute('val', 25);
|
||||
$objWriter->endElement();
|
||||
$scale = ($plotGroup === null) ? '' : (string) $plotGroup->getPlotStyle();
|
||||
if ($scale !== '') {
|
||||
$objWriter->startElement('c:bubbleScale');
|
||||
$objWriter->writeAttribute('val', $scale);
|
||||
$objWriter->endElement();
|
||||
}
|
||||
|
||||
$objWriter->startElement('c:showNegBubbles');
|
||||
$objWriter->writeAttribute('val', 0);
|
||||
|
|
@ -276,9 +313,10 @@ class Chart extends WriterPart
|
|||
$objWriter->endElement();
|
||||
}
|
||||
|
||||
// Generate 2 unique numbers to use for axId values
|
||||
$id1 = '75091328';
|
||||
$id2 = '75089408';
|
||||
// Generate 3 unique numbers to use for axId values
|
||||
$id1 = '110438656';
|
||||
$id2 = '110444544';
|
||||
$id3 = '110365312'; // used in Surface Chart
|
||||
|
||||
if (($chartType !== DataSeries::TYPE_PIECHART) && ($chartType !== DataSeries::TYPE_PIECHART_3D) && ($chartType !== DataSeries::TYPE_DONUTCHART)) {
|
||||
$objWriter->startElement('c:axId');
|
||||
|
|
@ -287,6 +325,11 @@ class Chart extends WriterPart
|
|||
$objWriter->startElement('c:axId');
|
||||
$objWriter->writeAttribute('val', $id2);
|
||||
$objWriter->endElement();
|
||||
if ($chartType === DataSeries::TYPE_SURFACECHART_3D || $chartType === DataSeries::TYPE_SURFACECHART) {
|
||||
$objWriter->startElement('c:axId');
|
||||
$objWriter->writeAttribute('val', $id3);
|
||||
$objWriter->endElement();
|
||||
}
|
||||
} else {
|
||||
$objWriter->startElement('c:firstSliceAng');
|
||||
$objWriter->writeAttribute('val', 0);
|
||||
|
|
@ -304,12 +347,15 @@ class Chart extends WriterPart
|
|||
|
||||
if (($chartType !== DataSeries::TYPE_PIECHART) && ($chartType !== DataSeries::TYPE_PIECHART_3D) && ($chartType !== DataSeries::TYPE_DONUTCHART)) {
|
||||
if ($chartType === DataSeries::TYPE_BUBBLECHART) {
|
||||
$this->writeValueAxis($objWriter, $xAxisLabel, $chartType, $id1, $id2, $catIsMultiLevelSeries, $xAxis, $majorGridlines, $minorGridlines);
|
||||
$this->writeValueAxis($objWriter, $xAxisLabel, $chartType, $id2, $id1, $catIsMultiLevelSeries, $xAxis, $majorGridlines, $minorGridlines);
|
||||
} else {
|
||||
$this->writeCategoryAxis($objWriter, $xAxisLabel, $id1, $id2, $catIsMultiLevelSeries, $xAxis);
|
||||
}
|
||||
|
||||
$this->writeValueAxis($objWriter, $yAxisLabel, $chartType, $id1, $id2, $valIsMultiLevelSeries, $yAxis, $majorGridlines, $minorGridlines);
|
||||
if ($chartType === DataSeries::TYPE_SURFACECHART_3D || $chartType === DataSeries::TYPE_SURFACECHART) {
|
||||
$this->writeSerAxis($objWriter, $id2, $id3);
|
||||
}
|
||||
}
|
||||
|
||||
$objWriter->endElement();
|
||||
|
|
@ -369,9 +415,15 @@ class Chart extends WriterPart
|
|||
*/
|
||||
private function writeCategoryAxis(XMLWriter $objWriter, ?Title $xAxisLabel, $id1, $id2, $isMultiLevelSeries, Axis $yAxis): void
|
||||
{
|
||||
$objWriter->startElement('c:catAx');
|
||||
// N.B. writeCategoryAxis may be invoked with the last parameter($yAxis) using $xAxis for ScatterChart, etc
|
||||
// In that case, xAxis is NOT a category.
|
||||
if ($yAxis->getAxisIsNumericFormat()) {
|
||||
$objWriter->startElement('c:valAx');
|
||||
} else {
|
||||
$objWriter->startElement('c:catAx');
|
||||
}
|
||||
|
||||
if ($id1 > 0) {
|
||||
if ($id1 !== '0') {
|
||||
$objWriter->startElement('c:axId');
|
||||
$objWriter->writeAttribute('val', $id1);
|
||||
$objWriter->endElement();
|
||||
|
|
@ -403,20 +455,20 @@ class Chart extends WriterPart
|
|||
$objWriter->endElement();
|
||||
|
||||
$objWriter->startElement('a:p');
|
||||
$objWriter->startElement('a:r');
|
||||
$objWriter->startElement('a:pPr');
|
||||
$objWriter->startElement('a:defRPr');
|
||||
$objWriter->endElement();
|
||||
$objWriter->endElement();
|
||||
|
||||
$caption = $xAxisLabel->getCaption();
|
||||
if (is_array($caption)) {
|
||||
$caption = $caption[0];
|
||||
}
|
||||
$objWriter->startElement('a:t');
|
||||
$objWriter->writeRawData(StringHelper::controlCharacterPHP2OOXML($caption));
|
||||
$objWriter->endElement();
|
||||
$this->getParentWriter()->getWriterPartstringtable()->writeRichTextForCharts($objWriter, $caption, 'a');
|
||||
|
||||
$objWriter->endElement();
|
||||
$objWriter->endElement();
|
||||
$objWriter->endElement();
|
||||
$objWriter->endElement();
|
||||
|
||||
$layout = $xAxisLabel->getLayout();
|
||||
$this->writeLayout($objWriter, $layout);
|
||||
|
|
@ -445,7 +497,7 @@ class Chart extends WriterPart
|
|||
$objWriter->writeAttribute('val', $yAxis->getAxisOptionsProperty('axis_labels'));
|
||||
$objWriter->endElement();
|
||||
|
||||
if ($id2 > 0) {
|
||||
if ($id2 !== '0') {
|
||||
$objWriter->startElement('c:crossAx');
|
||||
$objWriter->writeAttribute('val', $id2);
|
||||
$objWriter->endElement();
|
||||
|
|
@ -487,7 +539,7 @@ class Chart extends WriterPart
|
|||
{
|
||||
$objWriter->startElement('c:valAx');
|
||||
|
||||
if ($id2 > 0) {
|
||||
if ($id2 !== '0') {
|
||||
$objWriter->startElement('c:axId');
|
||||
$objWriter->writeAttribute('val', $id2);
|
||||
$objWriter->endElement();
|
||||
|
|
@ -746,18 +798,17 @@ class Chart extends WriterPart
|
|||
$objWriter->endElement();
|
||||
|
||||
$objWriter->startElement('a:p');
|
||||
$objWriter->startElement('a:r');
|
||||
$objWriter->startElement('a:pPr');
|
||||
$objWriter->startElement('a:defRPr');
|
||||
$objWriter->endElement();
|
||||
$objWriter->endElement();
|
||||
|
||||
$caption = $yAxisLabel->getCaption();
|
||||
if (is_array($caption)) {
|
||||
$caption = $caption[0];
|
||||
}
|
||||
$this->getParentWriter()->getWriterPartstringtable()->writeRichTextForCharts($objWriter, $caption, 'a');
|
||||
|
||||
$objWriter->startElement('a:t');
|
||||
$objWriter->writeRawData(StringHelper::controlCharacterPHP2OOXML($caption));
|
||||
$objWriter->endElement();
|
||||
|
||||
$objWriter->endElement();
|
||||
$objWriter->endElement();
|
||||
$objWriter->endElement();
|
||||
$objWriter->endElement();
|
||||
|
|
@ -913,9 +964,9 @@ class Chart extends WriterPart
|
|||
$objWriter->endElement(); //effectList
|
||||
$objWriter->endElement(); //end spPr
|
||||
|
||||
if ($id1 > 0) {
|
||||
if ($id1 !== '0') {
|
||||
$objWriter->startElement('c:crossAx');
|
||||
$objWriter->writeAttribute('val', $id2);
|
||||
$objWriter->writeAttribute('val', $id1);
|
||||
$objWriter->endElement();
|
||||
|
||||
if ($xAxis->getAxisOptionsProperty('horizontal_crosses_value') !== null) {
|
||||
|
|
@ -956,6 +1007,54 @@ class Chart extends WriterPart
|
|||
$objWriter->endElement();
|
||||
}
|
||||
|
||||
/**
|
||||
* Write Ser Axis, for Surface chart.
|
||||
*/
|
||||
private function writeSerAxis(XMLWriter $objWriter, string $id2, string $id3): void
|
||||
{
|
||||
$objWriter->startElement('c:serAx');
|
||||
|
||||
$objWriter->startElement('c:axId');
|
||||
$objWriter->writeAttribute('val', $id3);
|
||||
$objWriter->endElement(); // axId
|
||||
|
||||
$objWriter->startElement('c:scaling');
|
||||
$objWriter->startElement('c:orientation');
|
||||
$objWriter->writeAttribute('val', 'minMax');
|
||||
$objWriter->endElement(); // orientation
|
||||
$objWriter->endElement(); // scaling
|
||||
|
||||
$objWriter->startElement('c:delete');
|
||||
$objWriter->writeAttribute('val', '0');
|
||||
$objWriter->endElement(); // delete
|
||||
|
||||
$objWriter->startElement('c:axPos');
|
||||
$objWriter->writeAttribute('val', 'b');
|
||||
$objWriter->endElement(); // axPos
|
||||
|
||||
$objWriter->startElement('c:majorTickMark');
|
||||
$objWriter->writeAttribute('val', 'out');
|
||||
$objWriter->endElement(); // majorTickMark
|
||||
|
||||
$objWriter->startElement('c:minorTickMark');
|
||||
$objWriter->writeAttribute('val', 'none');
|
||||
$objWriter->endElement(); // minorTickMark
|
||||
|
||||
$objWriter->startElement('c:tickLblPos');
|
||||
$objWriter->writeAttribute('val', 'nextTo');
|
||||
$objWriter->endElement(); // tickLblPos
|
||||
|
||||
$objWriter->startElement('c:crossAx');
|
||||
$objWriter->writeAttribute('val', $id2);
|
||||
$objWriter->endElement(); // crossAx
|
||||
|
||||
$objWriter->startElement('c:crosses');
|
||||
$objWriter->writeAttribute('val', 'autoZero');
|
||||
$objWriter->endElement(); // crosses
|
||||
|
||||
$objWriter->endElement(); //serAx
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the data series type(s) for a chart plot series.
|
||||
*
|
||||
|
|
@ -1016,7 +1115,7 @@ class Chart extends WriterPart
|
|||
* @param bool $valIsMultiLevelSeries Is value set a multi-series set
|
||||
* @param string $plotGroupingType Type of grouping for multi-series values
|
||||
*/
|
||||
private function writePlotGroup(?DataSeries $plotGroup, $groupType, XMLWriter $objWriter, &$catIsMultiLevelSeries, &$valIsMultiLevelSeries, &$plotGroupingType): void
|
||||
private function writePlotGroup(?DataSeries $plotGroup, string $groupType, XMLWriter $objWriter, &$catIsMultiLevelSeries, &$valIsMultiLevelSeries, &$plotGroupingType): void
|
||||
{
|
||||
if ($plotGroup === null) {
|
||||
return;
|
||||
|
|
@ -1104,16 +1203,29 @@ class Chart extends WriterPart
|
|||
}
|
||||
|
||||
// Formatting for the points
|
||||
if (($groupType == DataSeries::TYPE_LINECHART) || ($groupType == DataSeries::TYPE_STOCKCHART)) {
|
||||
if (
|
||||
$groupType == DataSeries::TYPE_LINECHART
|
||||
|| $groupType == DataSeries::TYPE_STOCKCHART
|
||||
|| ($groupType === DataSeries::TYPE_SCATTERCHART && $plotSeriesValues !== false && !$plotSeriesValues->getScatterLines())
|
||||
|| ($plotSeriesValues !== false && $plotSeriesValues->getSchemeClr())
|
||||
) {
|
||||
$plotLineWidth = 12700;
|
||||
if ($plotSeriesValues) {
|
||||
$plotLineWidth = $plotSeriesValues->getLineWidth();
|
||||
}
|
||||
|
||||
$objWriter->startElement('c:spPr');
|
||||
$schemeClr = $plotLabel ? $plotLabel->getSchemeClr() : null;
|
||||
if ($schemeClr) {
|
||||
$objWriter->startElement('a:solidFill');
|
||||
$objWriter->startElement('a:schemeClr');
|
||||
$objWriter->writeAttribute('val', $schemeClr);
|
||||
$objWriter->endElement();
|
||||
$objWriter->endElement();
|
||||
}
|
||||
$objWriter->startElement('a:ln');
|
||||
$objWriter->writeAttribute('w', $plotLineWidth);
|
||||
if ($groupType == DataSeries::TYPE_STOCKCHART) {
|
||||
if ($groupType == DataSeries::TYPE_STOCKCHART || $groupType === DataSeries::TYPE_SCATTERCHART) {
|
||||
$objWriter->startElement('a:noFill');
|
||||
$objWriter->endElement();
|
||||
} elseif ($plotLabel) {
|
||||
|
|
@ -1142,6 +1254,16 @@ class Chart extends WriterPart
|
|||
$objWriter->startElement('c:size');
|
||||
$objWriter->writeAttribute('val', (string) $plotSeriesValues->getPointSize());
|
||||
$objWriter->endElement();
|
||||
$fillColor = $plotSeriesValues->getFillColor();
|
||||
if (is_string($fillColor) && $fillColor !== '') {
|
||||
$objWriter->startElement('c:spPr');
|
||||
$objWriter->startElement('a:solidFill');
|
||||
$objWriter->startElement('a:srgbClr');
|
||||
$objWriter->writeAttribute('val', $fillColor);
|
||||
$objWriter->endElement(); // srgbClr
|
||||
$objWriter->endElement(); // solidFill
|
||||
$objWriter->endElement(); // spPr
|
||||
}
|
||||
}
|
||||
|
||||
$objWriter->endElement();
|
||||
|
|
@ -1176,7 +1298,14 @@ class Chart extends WriterPart
|
|||
$objWriter->startElement('c:cat');
|
||||
}
|
||||
|
||||
$this->writePlotSeriesValues($plotSeriesCategory, $objWriter, $groupType, 'str');
|
||||
// xVals (Categories) are not always 'str'
|
||||
// Test X-axis Label's Datatype to decide 'str' vs 'num'
|
||||
$CategoryDatatype = $plotSeriesCategory->getDataType();
|
||||
if ($CategoryDatatype == DataSeriesValues::DATASERIES_TYPE_NUMBER) {
|
||||
$this->writePlotSeriesValues($plotSeriesCategory, $objWriter, $groupType, 'num');
|
||||
} else {
|
||||
$this->writePlotSeriesValues($plotSeriesCategory, $objWriter, $groupType, 'str');
|
||||
}
|
||||
$objWriter->endElement();
|
||||
}
|
||||
|
||||
|
|
@ -1192,10 +1321,31 @@ class Chart extends WriterPart
|
|||
|
||||
$this->writePlotSeriesValues($plotSeriesValues, $objWriter, $groupType, 'num');
|
||||
$objWriter->endElement();
|
||||
if ($groupType === DataSeries::TYPE_SCATTERCHART && $plotGroup->getPlotStyle() === 'smoothMarker') {
|
||||
$objWriter->startElement('c:smooth');
|
||||
$objWriter->writeAttribute('val', '1');
|
||||
$objWriter->endElement();
|
||||
}
|
||||
}
|
||||
|
||||
if ($groupType === DataSeries::TYPE_BUBBLECHART) {
|
||||
$this->writeBubbles($plotSeriesValues, $objWriter);
|
||||
if (!empty($plotGroup->getPlotBubbleSizes()[$plotSeriesIdx])) {
|
||||
$objWriter->startElement('c:bubbleSize');
|
||||
$this->writePlotSeriesValues(
|
||||
$plotGroup->getPlotBubbleSizes()[$plotSeriesIdx],
|
||||
$objWriter,
|
||||
$groupType,
|
||||
'num'
|
||||
);
|
||||
$objWriter->endElement();
|
||||
if ($plotSeriesValues !== false) {
|
||||
$objWriter->startElement('c:bubble3D');
|
||||
$objWriter->writeAttribute('val', $plotSeriesValues->getBubble3D() ? '1' : '0');
|
||||
$objWriter->endElement();
|
||||
}
|
||||
} else {
|
||||
$this->writeBubbles($plotSeriesValues, $objWriter);
|
||||
}
|
||||
}
|
||||
|
||||
$objWriter->endElement();
|
||||
|
|
@ -1289,38 +1439,43 @@ class Chart extends WriterPart
|
|||
$objWriter->writeRawData($plotSeriesValues->getDataSource());
|
||||
$objWriter->endElement();
|
||||
|
||||
$objWriter->startElement('c:' . $dataType . 'Cache');
|
||||
$count = $plotSeriesValues->getPointCount();
|
||||
$source = $plotSeriesValues->getDataSource();
|
||||
$values = $plotSeriesValues->getDataValues();
|
||||
if ($count > 1 || ($count === 1 && "=$source" !== (string) $values[0])) {
|
||||
$objWriter->startElement('c:' . $dataType . 'Cache');
|
||||
|
||||
if (($groupType != DataSeries::TYPE_PIECHART) && ($groupType != DataSeries::TYPE_PIECHART_3D) && ($groupType != DataSeries::TYPE_DONUTCHART)) {
|
||||
if (($plotSeriesValues->getFormatCode() !== null) && ($plotSeriesValues->getFormatCode() !== '')) {
|
||||
$objWriter->startElement('c:formatCode');
|
||||
$objWriter->writeRawData($plotSeriesValues->getFormatCode());
|
||||
$objWriter->endElement();
|
||||
}
|
||||
}
|
||||
|
||||
$objWriter->startElement('c:ptCount');
|
||||
$objWriter->writeAttribute('val', $plotSeriesValues->getPointCount());
|
||||
$objWriter->endElement();
|
||||
|
||||
$dataValues = $plotSeriesValues->getDataValues();
|
||||
if (!empty($dataValues)) {
|
||||
if (is_array($dataValues)) {
|
||||
foreach ($dataValues as $plotSeriesKey => $plotSeriesValue) {
|
||||
$objWriter->startElement('c:pt');
|
||||
$objWriter->writeAttribute('idx', $plotSeriesKey);
|
||||
|
||||
$objWriter->startElement('c:v');
|
||||
$objWriter->writeRawData($plotSeriesValue);
|
||||
$objWriter->endElement();
|
||||
if (($groupType != DataSeries::TYPE_PIECHART) && ($groupType != DataSeries::TYPE_PIECHART_3D) && ($groupType != DataSeries::TYPE_DONUTCHART)) {
|
||||
if (($plotSeriesValues->getFormatCode() !== null) && ($plotSeriesValues->getFormatCode() !== '')) {
|
||||
$objWriter->startElement('c:formatCode');
|
||||
$objWriter->writeRawData($plotSeriesValues->getFormatCode());
|
||||
$objWriter->endElement();
|
||||
}
|
||||
}
|
||||
|
||||
$objWriter->startElement('c:ptCount');
|
||||
$objWriter->writeAttribute('val', $plotSeriesValues->getPointCount());
|
||||
$objWriter->endElement();
|
||||
|
||||
$dataValues = $plotSeriesValues->getDataValues();
|
||||
if (!empty($dataValues)) {
|
||||
if (is_array($dataValues)) {
|
||||
foreach ($dataValues as $plotSeriesKey => $plotSeriesValue) {
|
||||
$objWriter->startElement('c:pt');
|
||||
$objWriter->writeAttribute('idx', $plotSeriesKey);
|
||||
|
||||
$objWriter->startElement('c:v');
|
||||
$objWriter->writeRawData($plotSeriesValue);
|
||||
$objWriter->endElement();
|
||||
$objWriter->endElement();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$objWriter->endElement(); // *Cache
|
||||
}
|
||||
|
||||
$objWriter->endElement();
|
||||
|
||||
$objWriter->endElement();
|
||||
$objWriter->endElement(); // *Ref
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1362,7 +1517,7 @@ class Chart extends WriterPart
|
|||
$objWriter->endElement();
|
||||
|
||||
$objWriter->startElement('c:bubble3D');
|
||||
$objWriter->writeAttribute('val', 0);
|
||||
$objWriter->writeAttribute('val', $plotSeriesValues->getBubble3D() ? '1' : '0');
|
||||
$objWriter->endElement();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -89,22 +89,49 @@ class Drawing extends WriterPart
|
|||
$tl = $chart->getTopLeftPosition();
|
||||
$tlColRow = Coordinate::indexesFromString($tl['cell']);
|
||||
$br = $chart->getBottomRightPosition();
|
||||
$brColRow = Coordinate::indexesFromString($br['cell']);
|
||||
|
||||
$objWriter->startElement('xdr:twoCellAnchor');
|
||||
$isTwoCellAnchor = $br['cell'] !== '';
|
||||
if ($isTwoCellAnchor) {
|
||||
$brColRow = Coordinate::indexesFromString($br['cell']);
|
||||
|
||||
$objWriter->startElement('xdr:from');
|
||||
$objWriter->writeElement('xdr:col', (string) ($tlColRow[0] - 1));
|
||||
$objWriter->writeElement('xdr:colOff', self::stringEmu($tl['xOffset']));
|
||||
$objWriter->writeElement('xdr:row', (string) ($tlColRow[1] - 1));
|
||||
$objWriter->writeElement('xdr:rowOff', self::stringEmu($tl['yOffset']));
|
||||
$objWriter->endElement();
|
||||
$objWriter->startElement('xdr:to');
|
||||
$objWriter->writeElement('xdr:col', (string) ($brColRow[0] - 1));
|
||||
$objWriter->writeElement('xdr:colOff', self::stringEmu($br['xOffset']));
|
||||
$objWriter->writeElement('xdr:row', (string) ($brColRow[1] - 1));
|
||||
$objWriter->writeElement('xdr:rowOff', self::stringEmu($br['yOffset']));
|
||||
$objWriter->endElement();
|
||||
$objWriter->startElement('xdr:twoCellAnchor');
|
||||
|
||||
$objWriter->startElement('xdr:from');
|
||||
$objWriter->writeElement('xdr:col', (string) ($tlColRow[0] - 1));
|
||||
$objWriter->writeElement('xdr:colOff', self::stringEmu($tl['xOffset']));
|
||||
$objWriter->writeElement('xdr:row', (string) ($tlColRow[1] - 1));
|
||||
$objWriter->writeElement('xdr:rowOff', self::stringEmu($tl['yOffset']));
|
||||
$objWriter->endElement();
|
||||
$objWriter->startElement('xdr:to');
|
||||
$objWriter->writeElement('xdr:col', (string) ($brColRow[0] - 1));
|
||||
$objWriter->writeElement('xdr:colOff', self::stringEmu($br['xOffset']));
|
||||
$objWriter->writeElement('xdr:row', (string) ($brColRow[1] - 1));
|
||||
$objWriter->writeElement('xdr:rowOff', self::stringEmu($br['yOffset']));
|
||||
$objWriter->endElement();
|
||||
} elseif ($chart->getOneCellAnchor()) {
|
||||
$objWriter->startElement('xdr:oneCellAnchor');
|
||||
|
||||
$objWriter->startElement('xdr:from');
|
||||
$objWriter->writeElement('xdr:col', (string) ($tlColRow[0] - 1));
|
||||
$objWriter->writeElement('xdr:colOff', self::stringEmu($tl['xOffset']));
|
||||
$objWriter->writeElement('xdr:row', (string) ($tlColRow[1] - 1));
|
||||
$objWriter->writeElement('xdr:rowOff', self::stringEmu($tl['yOffset']));
|
||||
$objWriter->endElement();
|
||||
$objWriter->startElement('xdr:ext');
|
||||
$objWriter->writeAttribute('cx', self::stringEmu($br['xOffset']));
|
||||
$objWriter->writeAttribute('cy', self::stringEmu($br['yOffset']));
|
||||
$objWriter->endElement();
|
||||
} else {
|
||||
$objWriter->startElement('xdr:absoluteAnchor');
|
||||
$objWriter->startElement('xdr:pos');
|
||||
$objWriter->writeAttribute('x', '0');
|
||||
$objWriter->writeAttribute('y', '0');
|
||||
$objWriter->endElement();
|
||||
$objWriter->startElement('xdr:ext');
|
||||
$objWriter->writeAttribute('cx', self::stringEmu($br['xOffset']));
|
||||
$objWriter->writeAttribute('cy', self::stringEmu($br['yOffset']));
|
||||
$objWriter->endElement();
|
||||
}
|
||||
|
||||
$objWriter->startElement('xdr:graphicFrame');
|
||||
$objWriter->writeAttribute('macro', '');
|
||||
|
|
|
|||
|
|
@ -203,7 +203,8 @@ class StringTable extends WriterPart
|
|||
if (!$richText instanceof RichText) {
|
||||
$textRun = $richText;
|
||||
$richText = new RichText();
|
||||
$richText->createTextRun($textRun);
|
||||
$run = $richText->createTextRun($textRun);
|
||||
$run->setFont(null);
|
||||
}
|
||||
|
||||
if ($prefix !== null) {
|
||||
|
|
@ -215,36 +216,75 @@ class StringTable extends WriterPart
|
|||
foreach ($elements as $element) {
|
||||
// r
|
||||
$objWriter->startElement($prefix . 'r');
|
||||
if ($element->getFont() !== null) {
|
||||
// rPr
|
||||
$objWriter->startElement($prefix . 'rPr');
|
||||
$size = $element->getFont()->getSize();
|
||||
if (is_numeric($size)) {
|
||||
$objWriter->writeAttribute('sz', (string) (int) ($size * 100));
|
||||
}
|
||||
|
||||
// rPr
|
||||
$objWriter->startElement($prefix . 'rPr');
|
||||
// Bold
|
||||
$objWriter->writeAttribute('b', ($element->getFont()->getBold() ? 1 : 0));
|
||||
// Italic
|
||||
$objWriter->writeAttribute('i', ($element->getFont()->getItalic() ? 1 : 0));
|
||||
// Underline
|
||||
$underlineType = $element->getFont()->getUnderline();
|
||||
switch ($underlineType) {
|
||||
case 'single':
|
||||
$underlineType = 'sng';
|
||||
|
||||
// Bold
|
||||
$objWriter->writeAttribute('b', ($element->getFont()->getBold() ? 1 : 0));
|
||||
// Italic
|
||||
$objWriter->writeAttribute('i', ($element->getFont()->getItalic() ? 1 : 0));
|
||||
// Underline
|
||||
$underlineType = $element->getFont()->getUnderline();
|
||||
switch ($underlineType) {
|
||||
case 'single':
|
||||
$underlineType = 'sng';
|
||||
break;
|
||||
case 'double':
|
||||
$underlineType = 'dbl';
|
||||
|
||||
break;
|
||||
case 'double':
|
||||
$underlineType = 'dbl';
|
||||
break;
|
||||
}
|
||||
$objWriter->writeAttribute('u', $underlineType);
|
||||
// Strikethrough
|
||||
$objWriter->writeAttribute('strike', ($element->getFont()->getStriketype() ?: 'noStrike'));
|
||||
// Superscript/subscript
|
||||
if ($element->getFont()->getBaseLine()) {
|
||||
$objWriter->writeAttribute('baseline', (string) $element->getFont()->getBaseLine());
|
||||
}
|
||||
|
||||
break;
|
||||
// Color
|
||||
$objWriter->startElement($prefix . 'solidFill');
|
||||
$objWriter->startElement($prefix . 'srgbClr');
|
||||
$objWriter->writeAttribute('val', $element->getFont()->getColor()->getRGB());
|
||||
$objWriter->endElement(); // srgbClr
|
||||
$objWriter->endElement(); // solidFill
|
||||
|
||||
// Underscore Color
|
||||
if ($element->getFont()->getUSchemeClr()) {
|
||||
$objWriter->startElement($prefix . 'uFill');
|
||||
$objWriter->startElement($prefix . 'solidFill');
|
||||
$objWriter->startElement($prefix . 'schemeClr');
|
||||
$objWriter->writeAttribute('val', $element->getFont()->getUSchemeClr());
|
||||
$objWriter->endElement(); // schemeClr
|
||||
$objWriter->endElement(); // solidFill
|
||||
$objWriter->endElement(); // uFill
|
||||
}
|
||||
|
||||
// fontName
|
||||
if ($element->getFont()->getLatin()) {
|
||||
$objWriter->startElement($prefix . 'latin');
|
||||
$objWriter->writeAttribute('typeface', $element->getFont()->getLatin());
|
||||
$objWriter->endElement();
|
||||
}
|
||||
if ($element->getFont()->getEastAsian()) {
|
||||
$objWriter->startElement($prefix . 'ea');
|
||||
$objWriter->writeAttribute('typeface', $element->getFont()->getEastAsian());
|
||||
$objWriter->endElement();
|
||||
}
|
||||
if ($element->getFont()->getComplexScript()) {
|
||||
$objWriter->startElement($prefix . 'cs');
|
||||
$objWriter->writeAttribute('typeface', $element->getFont()->getComplexScript());
|
||||
$objWriter->endElement();
|
||||
}
|
||||
|
||||
$objWriter->endElement();
|
||||
}
|
||||
$objWriter->writeAttribute('u', $underlineType);
|
||||
// Strikethrough
|
||||
$objWriter->writeAttribute('strike', ($element->getFont()->getStrikethrough() ? 'sngStrike' : 'noStrike'));
|
||||
|
||||
// rFont
|
||||
$objWriter->startElement($prefix . 'latin');
|
||||
$objWriter->writeAttribute('typeface', $element->getFont()->getName());
|
||||
$objWriter->endElement();
|
||||
|
||||
$objWriter->endElement();
|
||||
|
||||
// t
|
||||
$objWriter->startElement($prefix . 't');
|
||||
|
|
|
|||
|
|
@ -152,7 +152,7 @@ class Xlfn
|
|||
*/
|
||||
public static function addXlfn(string $funcstring): string
|
||||
{
|
||||
return preg_replace(self::XLFNREGEXP, '_xlfn.$1', $funcstring);
|
||||
return (string) preg_replace(self::XLFNREGEXP, '_xlfn.$1', $funcstring);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -19,10 +19,13 @@ abstract class AbstractFunctional extends TestCase
|
|||
*
|
||||
* @return Spreadsheet
|
||||
*/
|
||||
protected function writeAndReload(Spreadsheet $spreadsheet, $format, ?callable $readerCustomizer = null)
|
||||
protected function writeAndReload(Spreadsheet $spreadsheet, $format, ?callable $readerCustomizer = null, ?callable $writerCustomizer = null)
|
||||
{
|
||||
$filename = File::temporaryFilename();
|
||||
$writer = IOFactory::createWriter($spreadsheet, $format);
|
||||
if ($writerCustomizer) {
|
||||
$writerCustomizer($writer);
|
||||
}
|
||||
$writer->save($filename);
|
||||
|
||||
$reader = IOFactory::createReader($format);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,45 @@
|
|||
<?php
|
||||
|
||||
namespace PhpOffice\PhpSpreadsheetTests\Reader\Csv;
|
||||
|
||||
use PhpOffice\PhpSpreadsheet\Reader\Csv;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class CsvIssue2840Test extends TestCase
|
||||
{
|
||||
public function testNullStringIgnore(): void
|
||||
{
|
||||
$reader = new Csv();
|
||||
self::assertFalse($reader->getPreserveNullString());
|
||||
$inputData = <<<EOF
|
||||
john,,doe,,
|
||||
mary,,jane,,
|
||||
EOF;
|
||||
$expected = [
|
||||
['john', null, 'doe'],
|
||||
['mary', null, 'jane'],
|
||||
];
|
||||
$spreadsheet = $reader->loadSpreadsheetFromString($inputData);
|
||||
$sheet = $spreadsheet->getActiveSheet();
|
||||
self::assertSame($expected, $sheet->toArray());
|
||||
$spreadsheet->disconnectWorksheets();
|
||||
}
|
||||
|
||||
public function testNullStringLoad(): void
|
||||
{
|
||||
$reader = new Csv();
|
||||
$reader->setPreserveNullString(true);
|
||||
$inputData = <<<EOF
|
||||
john,,doe,,
|
||||
mary,,jane,,
|
||||
EOF;
|
||||
$expected = [
|
||||
['john', '', 'doe', '', ''],
|
||||
['mary', '', 'jane', '', ''],
|
||||
];
|
||||
$spreadsheet = $reader->loadSpreadsheetFromString($inputData);
|
||||
$sheet = $spreadsheet->getActiveSheet();
|
||||
self::assertSame($expected, $sheet->toArray());
|
||||
$spreadsheet->disconnectWorksheets();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
<?php
|
||||
|
||||
namespace PhpOffice\PhpSpreadsheetTests\Reader\Gnumeric;
|
||||
|
||||
use PhpOffice\PhpSpreadsheet\Reader\Gnumeric;
|
||||
use PhpOffice\PhpSpreadsheet\Spreadsheet;
|
||||
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class HiddenWorksheetTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @var Spreadsheet
|
||||
*/
|
||||
private $spreadsheet;
|
||||
|
||||
protected function setup(): void
|
||||
{
|
||||
$filename = 'tests/data/Reader/Gnumeric/HiddenSheet.gnumeric';
|
||||
$reader = new Gnumeric();
|
||||
$this->spreadsheet = $reader->load($filename);
|
||||
}
|
||||
|
||||
public function testPageSetup(): void
|
||||
{
|
||||
$assertions = $this->worksheetAssertions();
|
||||
|
||||
foreach ($this->spreadsheet->getAllSheets() as $worksheet) {
|
||||
if (!array_key_exists($worksheet->getTitle(), $assertions)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$sheetAssertions = $assertions[$worksheet->getTitle()];
|
||||
foreach ($sheetAssertions as $test => $expectedResult) {
|
||||
$actualResult = $worksheet->getSheetState();
|
||||
self::assertSame(
|
||||
$expectedResult,
|
||||
$actualResult,
|
||||
"Failed asserting sheet state {$expectedResult} for Worksheet '{$worksheet->getTitle()}' {$test}"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function worksheetAssertions(): array
|
||||
{
|
||||
return [
|
||||
'Sheet1' => [
|
||||
'sheetState' => Worksheet::SHEETSTATE_VISIBLE,
|
||||
],
|
||||
'Sheet2' => [
|
||||
'sheetState' => Worksheet::SHEETSTATE_HIDDEN,
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
<?php
|
||||
|
||||
namespace PhpOffice\PhpSpreadsheetTests\Reader\Ods;
|
||||
|
||||
use PhpOffice\PhpSpreadsheet\Reader\Ods;
|
||||
use PhpOffice\PhpSpreadsheet\Spreadsheet;
|
||||
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class HiddenWorksheetTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @var Spreadsheet
|
||||
*/
|
||||
private $spreadsheet;
|
||||
|
||||
protected function setup(): void
|
||||
{
|
||||
$filename = 'tests/data/Reader/Ods/HiddenSheet.ods';
|
||||
$reader = new Ods();
|
||||
$this->spreadsheet = $reader->load($filename);
|
||||
}
|
||||
|
||||
public function testPageSetup(): void
|
||||
{
|
||||
$assertions = $this->worksheetAssertions();
|
||||
|
||||
foreach ($this->spreadsheet->getAllSheets() as $worksheet) {
|
||||
if (!array_key_exists($worksheet->getTitle(), $assertions)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$sheetAssertions = $assertions[$worksheet->getTitle()];
|
||||
foreach ($sheetAssertions as $test => $expectedResult) {
|
||||
$actualResult = $worksheet->getSheetState();
|
||||
self::assertSame(
|
||||
$expectedResult,
|
||||
$actualResult,
|
||||
"Failed asserting sheet state {$expectedResult} for Worksheet '{$worksheet->getTitle()}' {$test}"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function worksheetAssertions(): array
|
||||
{
|
||||
return [
|
||||
'Sheet1' => [
|
||||
'sheetState' => Worksheet::SHEETSTATE_VISIBLE,
|
||||
],
|
||||
'Sheet2' => [
|
||||
'sheetState' => Worksheet::SHEETSTATE_HIDDEN,
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
<?php
|
||||
|
||||
namespace PhpOffice\PhpSpreadsheetTests\Reader\Xls;
|
||||
|
||||
use PhpOffice\PhpSpreadsheet\Reader\Xls;
|
||||
use PhpOffice\PhpSpreadsheet\Spreadsheet;
|
||||
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class HiddenWorksheetTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @var Spreadsheet
|
||||
*/
|
||||
private $spreadsheet;
|
||||
|
||||
protected function setup(): void
|
||||
{
|
||||
$filename = 'tests/data/Reader/XLS/HiddenSheet.xls';
|
||||
$reader = new Xls();
|
||||
$this->spreadsheet = $reader->load($filename);
|
||||
}
|
||||
|
||||
public function testPageSetup(): void
|
||||
{
|
||||
$assertions = $this->worksheetAssertions();
|
||||
|
||||
foreach ($this->spreadsheet->getAllSheets() as $worksheet) {
|
||||
if (!array_key_exists($worksheet->getTitle(), $assertions)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$sheetAssertions = $assertions[$worksheet->getTitle()];
|
||||
foreach ($sheetAssertions as $test => $expectedResult) {
|
||||
$actualResult = $worksheet->getSheetState();
|
||||
self::assertSame(
|
||||
$expectedResult,
|
||||
$actualResult,
|
||||
"Failed asserting sheet state {$expectedResult} for Worksheet '{$worksheet->getTitle()}' {$test}"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function worksheetAssertions(): array
|
||||
{
|
||||
return [
|
||||
'Sheet1' => [
|
||||
'sheetState' => Worksheet::SHEETSTATE_VISIBLE,
|
||||
],
|
||||
'Sheet2' => [
|
||||
'sheetState' => Worksheet::SHEETSTATE_HIDDEN,
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
<?php
|
||||
|
||||
namespace PhpOffice\PhpSpreadsheetTests\Reader\Xlsx;
|
||||
|
||||
use PhpOffice\PhpSpreadsheet\Reader\Xlsx;
|
||||
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class ChartSheetTest extends TestCase
|
||||
{
|
||||
public function testLoadChartSheetWithCharts(): void
|
||||
{
|
||||
$filename = 'tests/data/Reader/XLSX/ChartSheet.xlsx';
|
||||
$reader = new Xlsx();
|
||||
$reader->setIncludeCharts(true);
|
||||
$spreadsheet = $reader->load($filename);
|
||||
|
||||
self::assertCount(2, $spreadsheet->getAllSheets());
|
||||
$chartSheet = $spreadsheet->getSheetByName('Chart1');
|
||||
self::assertInstanceOf(Worksheet::class, $chartSheet);
|
||||
self::assertSame(1, $chartSheet->getChartCount());
|
||||
}
|
||||
|
||||
public function testLoadChartSheetWithoutCharts(): void
|
||||
{
|
||||
$filename = 'tests/data/Reader/XLSX/ChartSheet.xlsx';
|
||||
$reader = new Xlsx();
|
||||
$reader->setIncludeCharts(false);
|
||||
$spreadsheet = $reader->load($filename);
|
||||
|
||||
self::assertCount(1, $spreadsheet->getAllSheets());
|
||||
$chartSheet = $spreadsheet->getSheetByName('Chart1');
|
||||
self::assertNull($chartSheet);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,115 @@
|
|||
<?php
|
||||
|
||||
namespace PhpOffice\PhpSpreadsheetTests\Writer\Xlsx;
|
||||
|
||||
use PhpOffice\PhpSpreadsheet\Reader\Xlsx as XlsxReader;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class ChartsOpenpyxlTest extends TestCase
|
||||
{
|
||||
private const DIRECTORY = 'samples' . DIRECTORY_SEPARATOR . 'templates' . DIRECTORY_SEPARATOR;
|
||||
|
||||
public function testBubble2(): void
|
||||
{
|
||||
$file = self::DIRECTORY . '32readwriteBubbleChart2.xlsx';
|
||||
$reader = new XlsxReader();
|
||||
$reader->setIncludeCharts(true);
|
||||
$spreadsheet = $reader->load($file);
|
||||
$sheet = $spreadsheet->getActiveSheet();
|
||||
self::assertSame(1, $sheet->getChartCount());
|
||||
|
||||
self::assertSame('Sheet', $sheet->getTitle());
|
||||
$charts = $sheet->getChartCollection();
|
||||
self::assertCount(1, $charts);
|
||||
$chart = $charts[0];
|
||||
self::assertNotNull($chart);
|
||||
self::assertEmpty($chart->getTitle());
|
||||
self::assertTrue($chart->getOneCellAnchor());
|
||||
|
||||
$plotArea = $chart->getPlotArea();
|
||||
$plotSeries = $plotArea->getPlotGroup();
|
||||
self::assertCount(1, $plotSeries);
|
||||
$dataSeries = $plotSeries[0];
|
||||
$labels = $dataSeries->getPlotLabels();
|
||||
self::assertCount(2, $labels);
|
||||
self::assertSame(['2013'], $labels[0]->getDataValues());
|
||||
self::assertSame(['2014'], $labels[1]->getDataValues());
|
||||
|
||||
$plotCategories = $dataSeries->getPlotCategories();
|
||||
self::assertCount(2, $plotCategories);
|
||||
$categories = $plotCategories[0];
|
||||
self::assertSame('Number', $categories->getDataType());
|
||||
self::assertSame('\'Sheet\'!$A$2:$A$5', $categories->getDataSource());
|
||||
self::assertFalse($categories->getBubble3D());
|
||||
$categories = $plotCategories[1];
|
||||
self::assertCount(2, $plotCategories);
|
||||
self::assertSame('Number', $categories->getDataType());
|
||||
self::assertSame('\'Sheet\'!$A$7:$A$10', $categories->getDataSource());
|
||||
self::assertFalse($categories->getBubble3D());
|
||||
|
||||
$plotValues = $dataSeries->getPlotValues();
|
||||
self::assertCount(2, $plotValues);
|
||||
$values = $plotValues[0];
|
||||
self::assertSame('Number', $values->getDataType());
|
||||
self::assertSame('\'Sheet\'!$B$2:$B$5', $values->getDataSource());
|
||||
self::assertFalse($values->getBubble3D());
|
||||
$values = $plotValues[1];
|
||||
self::assertCount(2, $plotValues);
|
||||
self::assertSame('Number', $values->getDataType());
|
||||
self::assertSame('\'Sheet\'!$B$7:$B$10', $values->getDataSource());
|
||||
self::assertFalse($values->getBubble3D());
|
||||
|
||||
$plotValues = $dataSeries->getPlotBubbleSizes();
|
||||
self::assertCount(2, $plotValues);
|
||||
$values = $plotValues[0];
|
||||
self::assertSame('Number', $values->getDataType());
|
||||
self::assertSame('\'Sheet\'!$C$2:$C$5', $values->getDataSource());
|
||||
self::assertFalse($values->getBubble3D());
|
||||
$values = $plotValues[1];
|
||||
self::assertCount(2, $plotValues);
|
||||
self::assertSame('Number', $values->getDataType());
|
||||
self::assertSame('\'Sheet\'!$C$7:$C$10', $values->getDataSource());
|
||||
self::assertFalse($values->getBubble3D());
|
||||
|
||||
$spreadsheet->disconnectWorksheets();
|
||||
}
|
||||
|
||||
public function testXml(): void
|
||||
{
|
||||
$infile = self::DIRECTORY . '32readwriteBubbleChart2.xlsx';
|
||||
$file = 'zip://';
|
||||
$file .= $infile;
|
||||
$file .= '#xl/charts/chart1.xml';
|
||||
$data = file_get_contents($file);
|
||||
// confirm that file contains expected tags
|
||||
if ($data === false) {
|
||||
self::fail('Unable to read file');
|
||||
} else {
|
||||
self::assertSame(0, substr_count($data, 'c:'), 'unusual choice of prefix');
|
||||
self::assertSame(0, substr_count($data, 'bubbleScale'));
|
||||
self::assertSame(1, substr_count($data, '<tx><v>2013</v></tx>'), 'v tag for 2013');
|
||||
self::assertSame(1, substr_count($data, '<tx><v>2014</v></tx>'), 'v tag for 2014');
|
||||
self::assertSame(0, substr_count($data, 'numCache'), 'no cached values');
|
||||
}
|
||||
$file = 'zip://';
|
||||
$file .= $infile;
|
||||
$file .= '#xl/drawings/_rels/drawing1.xml.rels';
|
||||
$data = file_get_contents($file);
|
||||
// confirm that file contains expected tags
|
||||
if ($data === false) {
|
||||
self::fail('Unable to read file');
|
||||
} else {
|
||||
self::assertSame(1, substr_count($data, 'Target="/xl/charts/chart1.xml"'), 'Unusual absolute address in drawing rels file');
|
||||
}
|
||||
$file = 'zip://';
|
||||
$file .= $infile;
|
||||
$file .= '#xl/worksheets/_rels/sheet1.xml.rels';
|
||||
$data = file_get_contents($file);
|
||||
// confirm that file contains expected tags
|
||||
if ($data === false) {
|
||||
self::fail('Unable to read file');
|
||||
} else {
|
||||
self::assertSame(1, substr_count($data, 'Target="/xl/drawings/drawing1.xml"'), 'Unusual absolute address in worksheet rels file');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
<?php
|
||||
|
||||
namespace PhpOffice\PhpSpreadsheetTests\Reader\Xlsx;
|
||||
|
||||
use PhpOffice\PhpSpreadsheet\Reader\Xlsx;
|
||||
use PhpOffice\PhpSpreadsheet\Spreadsheet;
|
||||
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class HiddenWorksheetTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @var Spreadsheet
|
||||
*/
|
||||
private $spreadsheet;
|
||||
|
||||
protected function setup(): void
|
||||
{
|
||||
$filename = 'tests/data/Reader/XLSX/HiddenSheet.xlsx';
|
||||
$reader = new Xlsx();
|
||||
$this->spreadsheet = $reader->load($filename);
|
||||
}
|
||||
|
||||
public function testPageSetup(): void
|
||||
{
|
||||
$assertions = $this->worksheetAssertions();
|
||||
|
||||
foreach ($this->spreadsheet->getAllSheets() as $worksheet) {
|
||||
if (!array_key_exists($worksheet->getTitle(), $assertions)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$sheetAssertions = $assertions[$worksheet->getTitle()];
|
||||
foreach ($sheetAssertions as $test => $expectedResult) {
|
||||
$actualResult = $worksheet->getSheetState();
|
||||
self::assertSame(
|
||||
$expectedResult,
|
||||
$actualResult,
|
||||
"Failed asserting sheet state {$expectedResult} for Worksheet '{$worksheet->getTitle()}' {$test}"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function worksheetAssertions(): array
|
||||
{
|
||||
return [
|
||||
'Sheet1' => [
|
||||
'sheetState' => Worksheet::SHEETSTATE_VISIBLE,
|
||||
],
|
||||
'Sheet2' => [
|
||||
'sheetState' => Worksheet::SHEETSTATE_HIDDEN,
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
@ -26,7 +26,7 @@ class URLImageTest extends TestCase
|
|||
self::assertInstanceOf(Drawing::class, $drawing);
|
||||
// Check if the source is a URL or a file path
|
||||
self::assertTrue($drawing->getIsURL());
|
||||
self::assertSame('https://www.globalipmanager.com/DataFiles/Pics/20/Berniaga.comahp2.jpg', $drawing->getPath());
|
||||
self::assertSame('https://phpspreadsheet.readthedocs.io/en/latest/topics/images/01-03-filter-icon-1.png', $drawing->getPath());
|
||||
$imageContents = file_get_contents($drawing->getPath());
|
||||
self::assertNotFalse($imageContents);
|
||||
$filePath = tempnam(sys_get_temp_dir(), 'Drawing');
|
||||
|
|
@ -36,7 +36,7 @@ class URLImageTest extends TestCase
|
|||
unlink($filePath);
|
||||
self::assertNotFalse($mimeType);
|
||||
$extension = File::mime2ext($mimeType);
|
||||
self::assertSame('jpeg', $extension);
|
||||
self::assertSame('png', $extension);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -77,4 +77,29 @@ class WorksheetInfoNamesTest extends TestCase
|
|||
|
||||
self::assertEquals($expected, $actual);
|
||||
}
|
||||
|
||||
public function testListWorksheetNamesChartSheet(): void
|
||||
{
|
||||
$filename = 'tests/data/Reader/XLSX/ChartSheet.xlsx';
|
||||
$reader = new Xlsx();
|
||||
$actual = $reader->listWorksheetNames($filename);
|
||||
|
||||
$expected = ['Sheet1', 'Chart1'];
|
||||
|
||||
self::assertEquals($expected, $actual);
|
||||
}
|
||||
|
||||
public function testListWorksheetInfoChartSheet(): void
|
||||
{
|
||||
$filename = 'tests/data/Reader/XLSX/ChartSheet.xlsx';
|
||||
$reader = new Xlsx();
|
||||
$actual = $reader->listWorksheetInfo($filename);
|
||||
|
||||
$chartSheetInfo = $actual[1];
|
||||
|
||||
self::assertSame('Chart1', $chartSheetInfo['worksheetName']);
|
||||
self::assertSame(-1, $chartSheetInfo['lastColumnIndex']);
|
||||
self::assertSame(0, $chartSheetInfo['totalRows']);
|
||||
self::assertSame(0, $chartSheetInfo['totalColumns']);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ use PhpOffice\PhpSpreadsheet\Style\Color;
|
|||
use PhpOffice\PhpSpreadsheet\Style\Fill;
|
||||
use PhpOffice\PhpSpreadsheet\Style\Font;
|
||||
use PhpOffice\PhpSpreadsheet\Style\NumberFormat;
|
||||
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
|
||||
use PhpOffice\PhpSpreadsheet\Writer\Ods;
|
||||
use PhpOffice\PhpSpreadsheet\Writer\Ods\Content;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
|
@ -106,4 +107,26 @@ class ContentTest extends TestCase
|
|||
|
||||
self::assertXmlStringEqualsXmlFile($this->samplesPath . '/content-with-data.xml', $xml);
|
||||
}
|
||||
|
||||
public function testWriteWithHiddenWorksheet(): void
|
||||
{
|
||||
$workbook = new Spreadsheet();
|
||||
|
||||
// Worksheet 1
|
||||
$worksheet1 = $workbook->getActiveSheet();
|
||||
$worksheet1->setCellValue('A1', 1);
|
||||
|
||||
// Worksheet 2
|
||||
$worksheet2 = $workbook->createSheet();
|
||||
$worksheet2->setTitle('New Worksheet');
|
||||
$worksheet2->setCellValue('A1', 2);
|
||||
|
||||
$worksheet2->setSheetState(Worksheet::SHEETSTATE_HIDDEN);
|
||||
|
||||
// Write
|
||||
$content = new Content(new Ods($workbook));
|
||||
$xml = $content->write();
|
||||
|
||||
self::assertXmlStringEqualsXmlFile($this->samplesPath . '/content-hidden-worksheet.xml', $xml);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,171 @@
|
|||
<?php
|
||||
|
||||
namespace PhpOffice\PhpSpreadsheetTests\Writer\Xlsx;
|
||||
|
||||
use PhpOffice\PhpSpreadsheet\Chart\Axis;
|
||||
use PhpOffice\PhpSpreadsheet\Chart\Chart;
|
||||
use PhpOffice\PhpSpreadsheet\Chart\DataSeries;
|
||||
use PhpOffice\PhpSpreadsheet\Chart\DataSeriesValues;
|
||||
use PhpOffice\PhpSpreadsheet\Chart\Legend as ChartLegend;
|
||||
use PhpOffice\PhpSpreadsheet\Chart\PlotArea;
|
||||
use PhpOffice\PhpSpreadsheet\Chart\Properties;
|
||||
use PhpOffice\PhpSpreadsheet\Chart\Title;
|
||||
use PhpOffice\PhpSpreadsheet\Shared\File;
|
||||
use PhpOffice\PhpSpreadsheet\Spreadsheet;
|
||||
use PhpOffice\PhpSpreadsheet\Writer\Xlsx as XlsxWriter;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class Charts32CatAxValAxTest extends TestCase
|
||||
{
|
||||
// These tests can only be performed by examining xml.
|
||||
// They are based on sample 33_Chart_Create_Scatter2.
|
||||
|
||||
/** @var string */
|
||||
private $outputFileName = '';
|
||||
|
||||
protected function tearDown(): void
|
||||
{
|
||||
if ($this->outputFileName !== '') {
|
||||
unlink($this->outputFileName);
|
||||
$this->outputFileName = '';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider providerCatAxValAx
|
||||
*/
|
||||
public function test1CatAx1ValAx(?bool $numeric): void
|
||||
{
|
||||
$spreadsheet = new Spreadsheet();
|
||||
$worksheet = $spreadsheet->getActiveSheet();
|
||||
// changed data to simulate a trend chart - Xaxis are dates; Yaxis are 3 meausurements from each date
|
||||
$worksheet->fromArray(
|
||||
[
|
||||
['', 'metric1', 'metric2', 'metric3'],
|
||||
['=DATEVALUE("2021-01-01")', 12.1, 15.1, 21.1],
|
||||
['=DATEVALUE("2021-01-04")', 56.2, 73.2, 86.2],
|
||||
['=DATEVALUE("2021-01-07")', 52.2, 61.2, 69.2],
|
||||
['=DATEVALUE("2021-01-10")', 30.2, 32.2, 0.2],
|
||||
]
|
||||
);
|
||||
$worksheet->getStyle('A2:A5')->getNumberFormat()->setFormatCode(Properties::FORMAT_CODE_DATE_ISO8601);
|
||||
$worksheet->getColumnDimension('A')->setAutoSize(true);
|
||||
$worksheet->setSelectedCells('A1');
|
||||
|
||||
// Set the Labels for each data series we want to plot
|
||||
// Datatype
|
||||
// Cell reference for data
|
||||
// Format Code
|
||||
// Number of datapoints in series
|
||||
// Data values
|
||||
// Data Marker
|
||||
$dataSeriesLabels = [
|
||||
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$B$1', null, 1), // was 2010
|
||||
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$C$1', null, 1), // was 2011
|
||||
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$D$1', null, 1), // was 2012
|
||||
];
|
||||
// Set the X-Axis Labels
|
||||
// changed from STRING to NUMBER
|
||||
// added 2 additional x-axis values associated with each of the 3 metrics
|
||||
// added FORMATE_CODE_NUMBER
|
||||
$xAxisTickValues = [
|
||||
//new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$A$2:$A$5', null, 4), // Q1 to Q4
|
||||
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, 'Worksheet!$A$2:$A$5', Properties::FORMAT_CODE_DATE, 4),
|
||||
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, 'Worksheet!$A$2:$A$5', Properties::FORMAT_CODE_DATE, 4),
|
||||
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, 'Worksheet!$A$2:$A$5', Properties::FORMAT_CODE_DATE, 4),
|
||||
];
|
||||
// Set the Data values for each data series we want to plot
|
||||
// Datatype
|
||||
// Cell reference for data
|
||||
// Format Code
|
||||
// Number of datapoints in series
|
||||
// Data values
|
||||
// Data Marker
|
||||
// added FORMAT_CODE_NUMBER
|
||||
$dataSeriesValues = [
|
||||
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, 'Worksheet!$B$2:$B$5', Properties::FORMAT_CODE_NUMBER, 4),
|
||||
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, 'Worksheet!$C$2:$C$5', Properties::FORMAT_CODE_NUMBER, 4),
|
||||
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, 'Worksheet!$D$2:$D$5', Properties::FORMAT_CODE_NUMBER, 4),
|
||||
];
|
||||
// Added so that Xaxis shows dates instead of Excel-equivalent-year1900-numbers
|
||||
$xAxis = new Axis();
|
||||
//$xAxis->setAxisNumberProperties(Properties::FORMAT_CODE_DATE );
|
||||
if (is_bool($numeric)) {
|
||||
$xAxis->setAxisNumberProperties(Properties::FORMAT_CODE_DATE_ISO8601, $numeric);
|
||||
} else {
|
||||
$xAxis->setAxisNumberProperties(Properties::FORMAT_CODE_DATE_ISO8601);
|
||||
}
|
||||
|
||||
// Build the dataseries
|
||||
$series = new DataSeries(
|
||||
DataSeries::TYPE_SCATTERCHART, // plotType
|
||||
null, // plotGrouping (Scatter charts don't have any grouping)
|
||||
range(0, count($dataSeriesValues) - 1), // plotOrder
|
||||
$dataSeriesLabels, // plotLabel
|
||||
$xAxisTickValues, // plotCategory
|
||||
$dataSeriesValues, // plotValues
|
||||
null, // plotDirection
|
||||
false, // smooth line
|
||||
//DataSeries::STYLE_LINEMARKER // plotStyle
|
||||
DataSeries::STYLE_MARKER // plotStyle
|
||||
);
|
||||
|
||||
// Set the series in the plot area
|
||||
$plotArea = new PlotArea(null, [$series]);
|
||||
// Set the chart legend
|
||||
$legend = new ChartLegend(ChartLegend::POSITION_TOPRIGHT, null, false);
|
||||
|
||||
$title = new Title('Test Scatter Trend Chart');
|
||||
$yAxisLabel = new Title('Value ($k)');
|
||||
|
||||
// Create the chart
|
||||
$chart = new Chart(
|
||||
'chart1', // name
|
||||
$title, // title
|
||||
$legend, // legend
|
||||
$plotArea, // plotArea
|
||||
true, // plotVisibleOnly
|
||||
DataSeries::EMPTY_AS_GAP, // displayBlanksAs
|
||||
null, // xAxisLabel
|
||||
$yAxisLabel, // yAxisLabel
|
||||
// added xAxis for correct date display
|
||||
$xAxis, // xAxis
|
||||
);
|
||||
|
||||
// Set the position where the chart should appear in the worksheet
|
||||
$chart->setTopLeftPosition('A7');
|
||||
$chart->setBottomRightPosition('P20');
|
||||
// Add the chart to the worksheet
|
||||
$worksheet->addChart($chart);
|
||||
|
||||
$writer = new XlsxWriter($spreadsheet);
|
||||
$writer->setIncludeCharts(true);
|
||||
$this->outputFileName = File::temporaryFilename();
|
||||
$writer->save($this->outputFileName);
|
||||
$spreadsheet->disconnectWorksheets();
|
||||
|
||||
$file = 'zip://';
|
||||
$file .= $this->outputFileName;
|
||||
$file .= '#xl/charts/chart1.xml';
|
||||
$data = file_get_contents($file);
|
||||
// confirm that file contains expected tags
|
||||
if ($data === false) {
|
||||
self::fail('Unable to read file');
|
||||
} elseif ($numeric === true) {
|
||||
self::assertSame(0, substr_count($data, '<c:catAx'));
|
||||
self::assertSame(2, substr_count($data, '<c:valAx'));
|
||||
} else {
|
||||
self::assertSame(1, substr_count($data, '<c:catAx'));
|
||||
self::assertSame(1, substr_count($data, '<c:valAx'));
|
||||
}
|
||||
}
|
||||
|
||||
public function providerCatAxValAx(): array
|
||||
{
|
||||
return [
|
||||
[true],
|
||||
[false],
|
||||
[null],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,80 @@
|
|||
<?php
|
||||
|
||||
namespace PhpOffice\PhpSpreadsheetTests\Writer\Xlsx;
|
||||
|
||||
use PhpOffice\PhpSpreadsheet\Reader\Xlsx as XlsxReader;
|
||||
use PhpOffice\PhpSpreadsheet\RichText\RichText;
|
||||
use PhpOffice\PhpSpreadsheet\RichText\Run;
|
||||
use PhpOffice\PhpSpreadsheet\Style\Font;
|
||||
use PhpOffice\PhpSpreadsheet\Writer\Xlsx as XlsxWriter;
|
||||
use PhpOffice\PhpSpreadsheetTests\Functional\AbstractFunctional;
|
||||
|
||||
class Charts32ColoredAxisLabelTest extends AbstractFunctional
|
||||
{
|
||||
private const DIRECTORY = 'samples' . DIRECTORY_SEPARATOR . 'templates' . DIRECTORY_SEPARATOR;
|
||||
|
||||
public function readCharts(XlsxReader $reader): void
|
||||
{
|
||||
$reader->setIncludeCharts(true);
|
||||
}
|
||||
|
||||
public function writeCharts(XlsxWriter $writer): void
|
||||
{
|
||||
$writer->setIncludeCharts(true);
|
||||
}
|
||||
|
||||
public function testStock5(): void
|
||||
{
|
||||
$file = self::DIRECTORY . '32readwriteStockChart5.xlsx';
|
||||
$reader = new XlsxReader();
|
||||
$reader->setIncludeCharts(true);
|
||||
$spreadsheet = $reader->load($file);
|
||||
$sheet = $spreadsheet->getActiveSheet();
|
||||
self::assertSame(1, $sheet->getChartCount());
|
||||
/** @var callable */
|
||||
$callableReader = [$this, 'readCharts'];
|
||||
/** @var callable */
|
||||
$callableWriter = [$this, 'writeCharts'];
|
||||
$reloadedSpreadsheet = $this->writeAndReload($spreadsheet, 'Xlsx', $callableReader, $callableWriter);
|
||||
$spreadsheet->disconnectWorksheets();
|
||||
|
||||
$sheet = $reloadedSpreadsheet->getActiveSheet();
|
||||
self::assertSame('Charts', $sheet->getTitle());
|
||||
$charts = $sheet->getChartCollection();
|
||||
self::assertCount(1, $charts);
|
||||
$chart = $charts[0];
|
||||
self::assertNotNull($chart);
|
||||
|
||||
$xAxisLabel = $chart->getXAxisLabel();
|
||||
$captionArray = $xAxisLabel->getCaption();
|
||||
self::assertIsArray($captionArray);
|
||||
self::assertCount(1, $captionArray);
|
||||
$caption = $captionArray[0];
|
||||
self::assertInstanceOf(RichText::class, $caption);
|
||||
self::assertSame('X-Axis Title in Green', $caption->getPlainText());
|
||||
$elements = $caption->getRichTextElements();
|
||||
self::assertCount(1, $elements);
|
||||
$run = $elements[0];
|
||||
self::assertInstanceOf(Run::class, $run);
|
||||
$font = $run->getFont();
|
||||
self::assertInstanceOf(Font::class, $font);
|
||||
self::assertSame('00B050', $font->getColor()->getRGB());
|
||||
|
||||
$yAxisLabel = $chart->getYAxisLabel();
|
||||
$captionArray = $yAxisLabel->getCaption();
|
||||
self::assertIsArray($captionArray);
|
||||
self::assertCount(1, $captionArray);
|
||||
$caption = $captionArray[0];
|
||||
self::assertInstanceOf(RichText::class, $caption);
|
||||
self::assertSame('Y-Axis Title in Red', $caption->getPlainText());
|
||||
$elements = $caption->getRichTextElements();
|
||||
self::assertCount(1, $elements);
|
||||
$run = $elements[0];
|
||||
self::assertInstanceOf(Run::class, $run);
|
||||
$font = $run->getFont();
|
||||
self::assertInstanceOf(Font::class, $font);
|
||||
self::assertSame('FF0000', $font->getColor()->getRGB());
|
||||
|
||||
$reloadedSpreadsheet->disconnectWorksheets();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,333 @@
|
|||
<?php
|
||||
|
||||
namespace PhpOffice\PhpSpreadsheetTests\Writer\Xlsx;
|
||||
|
||||
use PhpOffice\PhpSpreadsheet\Reader\Xlsx as XlsxReader;
|
||||
use PhpOffice\PhpSpreadsheet\RichText\RichText;
|
||||
use PhpOffice\PhpSpreadsheet\RichText\Run;
|
||||
use PhpOffice\PhpSpreadsheet\Style\Font;
|
||||
use PhpOffice\PhpSpreadsheet\Writer\Xlsx as XlsxWriter;
|
||||
use PhpOffice\PhpSpreadsheetTests\Functional\AbstractFunctional;
|
||||
|
||||
class Charts32ScatterTest extends AbstractFunctional
|
||||
{
|
||||
private const DIRECTORY = 'samples' . DIRECTORY_SEPARATOR . 'templates' . DIRECTORY_SEPARATOR;
|
||||
|
||||
public function readCharts(XlsxReader $reader): void
|
||||
{
|
||||
$reader->setIncludeCharts(true);
|
||||
}
|
||||
|
||||
public function writeCharts(XlsxWriter $writer): void
|
||||
{
|
||||
$writer->setIncludeCharts(true);
|
||||
}
|
||||
|
||||
public function testScatter1(): void
|
||||
{
|
||||
$file = self::DIRECTORY . '32readwriteScatterChart1.xlsx';
|
||||
$reader = new XlsxReader();
|
||||
$reader->setIncludeCharts(true);
|
||||
$spreadsheet = $reader->load($file);
|
||||
$sheet = $spreadsheet->getActiveSheet();
|
||||
self::assertSame(1, $sheet->getChartCount());
|
||||
/** @var callable */
|
||||
$callableReader = [$this, 'readCharts'];
|
||||
/** @var callable */
|
||||
$callableWriter = [$this, 'writeCharts'];
|
||||
$reloadedSpreadsheet = $this->writeAndReload($spreadsheet, 'Xlsx', $callableReader, $callableWriter);
|
||||
$spreadsheet->disconnectWorksheets();
|
||||
|
||||
$sheet = $reloadedSpreadsheet->getActiveSheet();
|
||||
self::assertSame('Charts', $sheet->getTitle());
|
||||
$charts = $sheet->getChartCollection();
|
||||
self::assertCount(1, $charts);
|
||||
$chart = $charts[0];
|
||||
self::assertNotNull($chart);
|
||||
$title = $chart->getTitle();
|
||||
$captionArray = $title->getCaption();
|
||||
self::assertIsArray($captionArray);
|
||||
self::assertCount(1, $captionArray);
|
||||
$caption = $captionArray[0];
|
||||
self::assertInstanceOf(RichText::class, $caption);
|
||||
self::assertSame('Scatter - No Join and Markers', $caption->getPlainText());
|
||||
$elements = $caption->getRichTextElements();
|
||||
self::assertCount(1, $elements);
|
||||
$run = $elements[0];
|
||||
self::assertInstanceOf(Run::class, $run);
|
||||
$font = $run->getFont();
|
||||
self::assertInstanceOf(Font::class, $font);
|
||||
self::assertSame('Calibri', $font->getLatin());
|
||||
self::assertEquals(12, $font->getSize());
|
||||
self::assertTrue($font->getBold());
|
||||
self::assertFalse($font->getItalic());
|
||||
self::assertFalse($font->getSuperscript());
|
||||
self::assertFalse($font->getSubscript());
|
||||
self::assertFalse($font->getStrikethrough());
|
||||
self::assertSame('none', $font->getUnderline());
|
||||
self::assertSame('000000', $font->getColor()->getRGB());
|
||||
|
||||
$plotArea = $chart->getPlotArea();
|
||||
$plotSeries = $plotArea->getPlotGroup();
|
||||
self::assertCount(1, $plotSeries);
|
||||
$dataSeries = $plotSeries[0];
|
||||
$plotValues = $dataSeries->getPlotValues();
|
||||
self::assertCount(3, $plotValues);
|
||||
$values = $plotValues[0];
|
||||
self::assertFalse($values->getScatterLines());
|
||||
self::assertSame(28575, $values->getLineWidth());
|
||||
self::assertSame(3, $values->getPointSize());
|
||||
self::assertSame('', $values->getFillColor());
|
||||
$values = $plotValues[1];
|
||||
self::assertFalse($values->getScatterLines());
|
||||
self::assertSame(28575, $values->getLineWidth());
|
||||
self::assertSame(3, $values->getPointSize());
|
||||
self::assertSame('', $values->getFillColor());
|
||||
$values = $plotValues[2];
|
||||
self::assertFalse($values->getScatterLines());
|
||||
self::assertSame(28575, $values->getLineWidth());
|
||||
self::assertSame(7, $values->getPointSize());
|
||||
self::assertSame('FFFF00', $values->getFillColor());
|
||||
|
||||
$reloadedSpreadsheet->disconnectWorksheets();
|
||||
}
|
||||
|
||||
public function testScatter6(): void
|
||||
{
|
||||
$file = self::DIRECTORY . '32readwriteScatterChart6.xlsx';
|
||||
$reader = new XlsxReader();
|
||||
$reader->setIncludeCharts(true);
|
||||
$spreadsheet = $reader->load($file);
|
||||
$sheet = $spreadsheet->getActiveSheet();
|
||||
self::assertSame(1, $sheet->getChartCount());
|
||||
/** @var callable */
|
||||
$callableReader = [$this, 'readCharts'];
|
||||
/** @var callable */
|
||||
$callableWriter = [$this, 'writeCharts'];
|
||||
$reloadedSpreadsheet = $this->writeAndReload($spreadsheet, 'Xlsx', $callableReader, $callableWriter);
|
||||
$spreadsheet->disconnectWorksheets();
|
||||
|
||||
$sheet = $reloadedSpreadsheet->getActiveSheet();
|
||||
self::assertSame('Charts', $sheet->getTitle());
|
||||
$charts = $sheet->getChartCollection();
|
||||
self::assertCount(1, $charts);
|
||||
$chart = $charts[0];
|
||||
self::assertNotNull($chart);
|
||||
$title = $chart->getTitle();
|
||||
$captionArray = $title->getCaption();
|
||||
self::assertIsArray($captionArray);
|
||||
self::assertCount(1, $captionArray);
|
||||
$caption = $captionArray[0];
|
||||
self::assertInstanceOf(RichText::class, $caption);
|
||||
self::assertSame('Scatter - Rich Text Title No Join and Markers', $caption->getPlainText());
|
||||
$elements = $caption->getRichTextElements();
|
||||
self::assertCount(3, $elements);
|
||||
|
||||
$run = $elements[0];
|
||||
self::assertInstanceOf(Run::class, $run);
|
||||
$font = $run->getFont();
|
||||
self::assertInstanceOf(Font::class, $font);
|
||||
self::assertSame('Calibri', $font->getLatin());
|
||||
self::assertEquals(12, $font->getSize());
|
||||
self::assertTrue($font->getBold());
|
||||
self::assertFalse($font->getItalic());
|
||||
self::assertFalse($font->getSuperscript());
|
||||
self::assertFalse($font->getSubscript());
|
||||
self::assertFalse($font->getStrikethrough());
|
||||
self::assertSame('none', $font->getUnderline());
|
||||
self::assertSame('000000', $font->getColor()->getRGB());
|
||||
|
||||
$run = $elements[1];
|
||||
self::assertInstanceOf(Run::class, $run);
|
||||
$font = $run->getFont();
|
||||
self::assertInstanceOf(Font::class, $font);
|
||||
self::assertSame('Courier New', $font->getLatin());
|
||||
self::assertEquals(10, $font->getSize());
|
||||
self::assertFalse($font->getBold());
|
||||
self::assertFalse($font->getItalic());
|
||||
self::assertFalse($font->getSuperscript());
|
||||
self::assertFalse($font->getSubscript());
|
||||
self::assertFalse($font->getStrikethrough());
|
||||
self::assertSame('single', $font->getUnderline());
|
||||
self::assertSame('00B0F0', $font->getColor()->getRGB());
|
||||
|
||||
$run = $elements[2];
|
||||
self::assertInstanceOf(Run::class, $run);
|
||||
$font = $run->getFont();
|
||||
self::assertInstanceOf(Font::class, $font);
|
||||
self::assertSame('Calibri', $font->getLatin());
|
||||
self::assertEquals(12, $font->getSize());
|
||||
self::assertTrue($font->getBold());
|
||||
self::assertFalse($font->getItalic());
|
||||
self::assertFalse($font->getSuperscript());
|
||||
self::assertFalse($font->getSubscript());
|
||||
self::assertFalse($font->getStrikethrough());
|
||||
self::assertSame('none', $font->getUnderline());
|
||||
self::assertSame('000000', $font->getColor()->getRGB());
|
||||
|
||||
$plotArea = $chart->getPlotArea();
|
||||
$plotSeries = $plotArea->getPlotGroup();
|
||||
self::assertCount(1, $plotSeries);
|
||||
$dataSeries = $plotSeries[0];
|
||||
$plotValues = $dataSeries->getPlotValues();
|
||||
self::assertCount(3, $plotValues);
|
||||
$values = $plotValues[0];
|
||||
self::assertFalse($values->getScatterLines());
|
||||
self::assertSame(28575, $values->getLineWidth());
|
||||
self::assertSame(3, $values->getPointSize());
|
||||
self::assertSame('', $values->getFillColor());
|
||||
$values = $plotValues[1];
|
||||
self::assertFalse($values->getScatterLines());
|
||||
self::assertSame(28575, $values->getLineWidth());
|
||||
self::assertSame(3, $values->getPointSize());
|
||||
self::assertSame('', $values->getFillColor());
|
||||
$values = $plotValues[2];
|
||||
self::assertFalse($values->getScatterLines());
|
||||
self::assertSame(28575, $values->getLineWidth());
|
||||
self::assertSame(7, $values->getPointSize());
|
||||
self::assertSame('FFFF00', $values->getFillColor());
|
||||
|
||||
$reloadedSpreadsheet->disconnectWorksheets();
|
||||
}
|
||||
|
||||
public function testScatter3(): void
|
||||
{
|
||||
$file = self::DIRECTORY . '32readwriteScatterChart3.xlsx';
|
||||
$reader = new XlsxReader();
|
||||
$reader->setIncludeCharts(true);
|
||||
$spreadsheet = $reader->load($file);
|
||||
$sheet = $spreadsheet->getActiveSheet();
|
||||
self::assertSame(1, $sheet->getChartCount());
|
||||
/** @var callable */
|
||||
$callableReader = [$this, 'readCharts'];
|
||||
/** @var callable */
|
||||
$callableWriter = [$this, 'writeCharts'];
|
||||
$reloadedSpreadsheet = $this->writeAndReload($spreadsheet, 'Xlsx', $callableReader, $callableWriter);
|
||||
$spreadsheet->disconnectWorksheets();
|
||||
|
||||
$sheet = $reloadedSpreadsheet->getActiveSheet();
|
||||
self::assertSame('Charts', $sheet->getTitle());
|
||||
$charts = $sheet->getChartCollection();
|
||||
self::assertCount(1, $charts);
|
||||
$chart = $charts[0];
|
||||
self::assertNotNull($chart);
|
||||
$title = $chart->getTitle();
|
||||
$captionArray = $title->getCaption();
|
||||
self::assertIsArray($captionArray);
|
||||
self::assertCount(1, $captionArray);
|
||||
$caption = $captionArray[0];
|
||||
self::assertInstanceOf(RichText::class, $caption);
|
||||
self::assertSame('Scatter - Join Straight Lines and Markers', $caption->getPlainText());
|
||||
$elements = $caption->getRichTextElements();
|
||||
self::assertCount(1, $elements);
|
||||
$run = $elements[0];
|
||||
self::assertInstanceOf(Run::class, $run);
|
||||
$font = $run->getFont();
|
||||
self::assertInstanceOf(Font::class, $font);
|
||||
self::assertSame('Calibri', $font->getLatin());
|
||||
self::assertEquals(12, $font->getSize());
|
||||
self::assertTrue($font->getBold());
|
||||
self::assertFalse($font->getItalic());
|
||||
self::assertFalse($font->getSuperscript());
|
||||
self::assertFalse($font->getSubscript());
|
||||
self::assertFalse($font->getStrikethrough());
|
||||
self::assertSame('none', $font->getUnderline());
|
||||
self::assertSame('000000', $font->getColor()->getRGB());
|
||||
|
||||
$plotArea = $chart->getPlotArea();
|
||||
$plotSeries = $plotArea->getPlotGroup();
|
||||
self::assertCount(1, $plotSeries);
|
||||
$dataSeries = $plotSeries[0];
|
||||
$plotValues = $dataSeries->getPlotValues();
|
||||
self::assertCount(3, $plotValues);
|
||||
$values = $plotValues[0];
|
||||
self::assertTrue($values->getScatterLines());
|
||||
self::assertSame(12700, $values->getLineWidth());
|
||||
self::assertSame(3, $values->getPointSize());
|
||||
self::assertSame('', $values->getFillColor());
|
||||
$values = $plotValues[1];
|
||||
self::assertTrue($values->getScatterLines());
|
||||
self::assertSame(12700, $values->getLineWidth());
|
||||
self::assertSame(3, $values->getPointSize());
|
||||
self::assertSame('', $values->getFillColor());
|
||||
$values = $plotValues[2];
|
||||
self::assertTrue($values->getScatterLines());
|
||||
self::assertSame(12700, $values->getLineWidth());
|
||||
self::assertSame(3, $values->getPointSize());
|
||||
self::assertSame('', $values->getFillColor());
|
||||
|
||||
$reloadedSpreadsheet->disconnectWorksheets();
|
||||
}
|
||||
|
||||
public function testScatter7(): void
|
||||
{
|
||||
$file = self::DIRECTORY . '32readwriteScatterChart7.xlsx';
|
||||
$reader = new XlsxReader();
|
||||
$reader->setIncludeCharts(true);
|
||||
$spreadsheet = $reader->load($file);
|
||||
$sheet = $spreadsheet->getActiveSheet();
|
||||
self::assertSame(1, $sheet->getChartCount());
|
||||
/** @var callable */
|
||||
$callableReader = [$this, 'readCharts'];
|
||||
/** @var callable */
|
||||
$callableWriter = [$this, 'writeCharts'];
|
||||
$reloadedSpreadsheet = $this->writeAndReload($spreadsheet, 'Xlsx', $callableReader, $callableWriter);
|
||||
$spreadsheet->disconnectWorksheets();
|
||||
|
||||
$sheet = $reloadedSpreadsheet->getActiveSheet();
|
||||
self::assertSame('Charts', $sheet->getTitle());
|
||||
$charts = $sheet->getChartCollection();
|
||||
self::assertCount(1, $charts);
|
||||
$chart = $charts[0];
|
||||
self::assertNotNull($chart);
|
||||
$title = $chart->getTitle();
|
||||
$captionArray = $title->getCaption();
|
||||
self::assertIsArray($captionArray);
|
||||
self::assertCount(1, $captionArray);
|
||||
$caption = $captionArray[0];
|
||||
self::assertInstanceOf(RichText::class, $caption);
|
||||
self::assertSame('Latin/EA/CS Title ABCאבגDEFァ', $caption->getPlainText());
|
||||
$elements = $caption->getRichTextElements();
|
||||
self::assertGreaterThan(0, count($elements));
|
||||
foreach ($elements as $run) {
|
||||
self::assertInstanceOf(Run::class, $run);
|
||||
$font = $run->getFont();
|
||||
self::assertInstanceOf(Font::class, $font);
|
||||
self::assertSame('Times New Roman', $font->getLatin());
|
||||
self::assertSame('Malgun Gothic', $font->getEastAsian());
|
||||
self::assertSame('Courier New', $font->getComplexScript());
|
||||
self::assertEquals(12, $font->getSize());
|
||||
self::assertTrue($font->getBold());
|
||||
self::assertFalse($font->getItalic());
|
||||
self::assertFalse($font->getSuperscript());
|
||||
self::assertFalse($font->getSubscript());
|
||||
self::assertFalse($font->getStrikethrough());
|
||||
self::assertSame('none', $font->getUnderline());
|
||||
self::assertSame('000000', $font->getColor()->getRGB());
|
||||
}
|
||||
|
||||
$plotArea = $chart->getPlotArea();
|
||||
$plotSeries = $plotArea->getPlotGroup();
|
||||
self::assertCount(1, $plotSeries);
|
||||
$dataSeries = $plotSeries[0];
|
||||
$plotValues = $dataSeries->getPlotValues();
|
||||
self::assertCount(3, $plotValues);
|
||||
$values = $plotValues[0];
|
||||
self::assertFalse($values->getScatterLines());
|
||||
self::assertSame(28575, $values->getLineWidth());
|
||||
self::assertSame(3, $values->getPointSize());
|
||||
self::assertSame('', $values->getFillColor());
|
||||
$values = $plotValues[1];
|
||||
self::assertFalse($values->getScatterLines());
|
||||
self::assertSame(28575, $values->getLineWidth());
|
||||
self::assertSame(3, $values->getPointSize());
|
||||
self::assertSame('', $values->getFillColor());
|
||||
$values = $plotValues[2];
|
||||
self::assertFalse($values->getScatterLines());
|
||||
self::assertSame(28575, $values->getLineWidth());
|
||||
self::assertSame(7, $values->getPointSize());
|
||||
self::assertSame('FFFF00', $values->getFillColor());
|
||||
|
||||
$reloadedSpreadsheet->disconnectWorksheets();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,147 @@
|
|||
<?php
|
||||
|
||||
namespace PhpOffice\PhpSpreadsheetTests\Writer\Xlsx;
|
||||
|
||||
use PhpOffice\PhpSpreadsheet\Chart\Properties;
|
||||
use PhpOffice\PhpSpreadsheet\Reader\Xlsx as XlsxReader;
|
||||
use PhpOffice\PhpSpreadsheet\Shared\File;
|
||||
use PhpOffice\PhpSpreadsheet\Writer\Xlsx as XlsxWriter;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class Charts32XmlTest extends TestCase
|
||||
{
|
||||
// These tests can only be performed by examining xml.
|
||||
private const DIRECTORY = 'samples' . DIRECTORY_SEPARATOR . 'templates' . DIRECTORY_SEPARATOR;
|
||||
|
||||
/** @var string */
|
||||
private $outputFileName = '';
|
||||
|
||||
protected function tearDown(): void
|
||||
{
|
||||
if ($this->outputFileName !== '') {
|
||||
unlink($this->outputFileName);
|
||||
$this->outputFileName = '';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider providerScatterCharts
|
||||
*/
|
||||
public function testBezierCount(int $expectedCount, string $inputFile): void
|
||||
{
|
||||
$file = self::DIRECTORY . $inputFile;
|
||||
$reader = new XlsxReader();
|
||||
$reader->setIncludeCharts(true);
|
||||
$spreadsheet = $reader->load($file);
|
||||
|
||||
$writer = new XlsxWriter($spreadsheet);
|
||||
$writer->setIncludeCharts(true);
|
||||
$this->outputFileName = File::temporaryFilename();
|
||||
$writer->save($this->outputFileName);
|
||||
$spreadsheet->disconnectWorksheets();
|
||||
|
||||
$file = 'zip://';
|
||||
$file .= $this->outputFileName;
|
||||
$file .= '#xl/charts/chart2.xml';
|
||||
$data = file_get_contents($file);
|
||||
// confirm that file contains expected tags
|
||||
if ($data === false) {
|
||||
self::fail('Unable to read file');
|
||||
} else {
|
||||
self::assertSame(1, substr_count($data, '<c:scatterStyle val='));
|
||||
self::assertSame($expectedCount ? 1 : 0, substr_count($data, '<c:scatterStyle val="smoothMarker"/>'));
|
||||
self::assertSame($expectedCount, substr_count($data, '<c:smooth val="1"/>'));
|
||||
}
|
||||
}
|
||||
|
||||
public function providerScatterCharts(): array
|
||||
{
|
||||
return [
|
||||
'no line' => [0, '32readwriteScatterChart1.xlsx'],
|
||||
'smooth line (Bezier)' => [3, '32readwriteScatterChart2.xlsx'],
|
||||
'straight line' => [0, '32readwriteScatterChart3.xlsx'],
|
||||
];
|
||||
}
|
||||
|
||||
public function testAreaPercentageNoCat(): void
|
||||
{
|
||||
$file = self::DIRECTORY . '32readwriteAreaPercentageChart1.xlsx';
|
||||
$reader = new XlsxReader();
|
||||
$reader->setIncludeCharts(true);
|
||||
$spreadsheet = $reader->load($file);
|
||||
|
||||
$writer = new XlsxWriter($spreadsheet);
|
||||
$writer->setIncludeCharts(true);
|
||||
$this->outputFileName = File::temporaryFilename();
|
||||
$writer->save($this->outputFileName);
|
||||
$spreadsheet->disconnectWorksheets();
|
||||
|
||||
$file = 'zip://';
|
||||
$file .= $this->outputFileName;
|
||||
$file .= '#xl/charts/chart1.xml';
|
||||
$data = file_get_contents($file);
|
||||
// confirm that file contains expected tags
|
||||
if ($data === false) {
|
||||
self::fail('Unable to read file');
|
||||
} else {
|
||||
self::assertSame(0, substr_count($data, '<c:cat>'));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider providerCatAxValAx
|
||||
*/
|
||||
public function testCatAxValAx(?bool $numeric): void
|
||||
{
|
||||
$file = self::DIRECTORY . '32readwriteScatterChart1.xlsx';
|
||||
$reader = new XlsxReader();
|
||||
$reader->setIncludeCharts(true);
|
||||
$spreadsheet = $reader->load($file);
|
||||
$sheet = $spreadsheet->getActiveSheet();
|
||||
$charts = $sheet->getChartCollection();
|
||||
self::assertCount(1, $charts);
|
||||
$chart = $charts[0];
|
||||
self::assertNotNull($chart);
|
||||
$xAxis = $chart->getChartAxisX();
|
||||
self::assertSame(Properties::FORMAT_CODE_GENERAL, $xAxis->getAxisNumberFormat());
|
||||
if (is_bool($numeric)) {
|
||||
$xAxis->setAxisNumberProperties(Properties::FORMAT_CODE_GENERAL, true);
|
||||
}
|
||||
$yAxis = $chart->getChartAxisY();
|
||||
self::assertSame(Properties::FORMAT_CODE_GENERAL, $yAxis->getAxisNumberFormat());
|
||||
if (is_bool($numeric)) {
|
||||
$xAxis->setAxisNumberProperties(Properties::FORMAT_CODE_GENERAL, $numeric);
|
||||
$yAxis->setAxisNumberProperties(Properties::FORMAT_CODE_GENERAL, $numeric);
|
||||
}
|
||||
|
||||
$writer = new XlsxWriter($spreadsheet);
|
||||
$writer->setIncludeCharts(true);
|
||||
$this->outputFileName = File::temporaryFilename();
|
||||
$writer->save($this->outputFileName);
|
||||
$spreadsheet->disconnectWorksheets();
|
||||
|
||||
$file = 'zip://';
|
||||
$file .= $this->outputFileName;
|
||||
$file .= '#xl/charts/chart2.xml';
|
||||
$data = file_get_contents($file);
|
||||
// confirm that file contains expected tags
|
||||
if ($data === false) {
|
||||
self::fail('Unable to read file');
|
||||
} elseif ($numeric === true) {
|
||||
self::assertSame(0, substr_count($data, '<c:catAx>'));
|
||||
self::assertSame(2, substr_count($data, '<c:valAx>'));
|
||||
} else {
|
||||
self::assertSame(1, substr_count($data, '<c:catAx>'));
|
||||
self::assertSame(1, substr_count($data, '<c:valAx>'));
|
||||
}
|
||||
}
|
||||
|
||||
public function providerCatAxValAx(): array
|
||||
{
|
||||
return [
|
||||
[true],
|
||||
[false],
|
||||
[null],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
@ -48,6 +48,30 @@ return [
|
|||
-6.7800000000000002,
|
||||
-2,
|
||||
],
|
||||
[
|
||||
31.25,
|
||||
12.5,
|
||||
null,
|
||||
2.5,
|
||||
],
|
||||
[
|
||||
31.25,
|
||||
12.5,
|
||||
2.5,
|
||||
null,
|
||||
],
|
||||
[
|
||||
12.5,
|
||||
12.5,
|
||||
null,
|
||||
null,
|
||||
],
|
||||
[
|
||||
0.0,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
],
|
||||
['#VALUE!', 1, 'y', 3],
|
||||
[6, 1, '2', 3],
|
||||
];
|
||||
|
|
|
|||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -3,6 +3,9 @@
|
|||
<office:scripts />
|
||||
<office:font-face-decls />
|
||||
<office:automatic-styles>
|
||||
<style:style style:family="table" style:name="ta1">
|
||||
<style:table-properties table:display="true" />
|
||||
</style:style>
|
||||
<style:style style:name="ce0" style:family="table-cell" style:parent-style-name="Default">
|
||||
<style:table-cell-properties style:rotation-align="none" style:vertical-align="bottom" />
|
||||
<style:paragraph-properties fo:text-align="start" />
|
||||
|
|
@ -12,7 +15,7 @@
|
|||
<office:body>
|
||||
<office:spreadsheet>
|
||||
<table:calculation-settings />
|
||||
<table:table table:name="Worksheet">
|
||||
<table:table table:name="Worksheet" table:style-name="ta1">
|
||||
<office:forms />
|
||||
<table:table-row>
|
||||
<table:table-cell table:style-name="ce0" />
|
||||
|
|
|
|||
|
|
@ -0,0 +1,42 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<office:document-content xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0" xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0" xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0" xmlns:number="urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0" xmlns:presentation="urn:oasis:names:tc:opendocument:xmlns:presentation:1.0" xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0" xmlns:chart="urn:oasis:names:tc:opendocument:xmlns:chart:1.0" xmlns:dr3d="urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0" xmlns:math="http://www.w3.org/1998/Math/MathML" xmlns:form="urn:oasis:names:tc:opendocument:xmlns:form:1.0" xmlns:script="urn:oasis:names:tc:opendocument:xmlns:script:1.0" xmlns:ooo="http://openoffice.org/2004/office" xmlns:ooow="http://openoffice.org/2004/writer" xmlns:oooc="http://openoffice.org/2004/calc" xmlns:dom="http://www.w3.org/2001/xml-events" xmlns:xforms="http://www.w3.org/2002/xforms" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:rpt="http://openoffice.org/2005/report" xmlns:of="urn:oasis:names:tc:opendocument:xmlns:of:1.2" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:grddl="http://www.w3.org/2003/g/data-view#" xmlns:tableooo="http://openoffice.org/2009/table" xmlns:field="urn:openoffice:names:experimental:ooo-ms-interop:xmlns:field:1.0" xmlns:formx="urn:openoffice:names:experimental:ooxml-odf-interop:xmlns:form:1.0" xmlns:css3t="http://www.w3.org/TR/css3-text/" office:version="1.2">
|
||||
<office:scripts />
|
||||
<office:font-face-decls />
|
||||
<office:automatic-styles>
|
||||
<style:style style:family="table" style:name="ta1">
|
||||
<style:table-properties table:display="true" />
|
||||
</style:style>
|
||||
<style:style style:family="table" style:name="ta2">
|
||||
<style:table-properties table:display="false"/>
|
||||
</style:style>
|
||||
<style:style style:name="ce0" style:family="table-cell" style:parent-style-name="Default">
|
||||
<style:table-cell-properties style:rotation-align="none" style:vertical-align="bottom" />
|
||||
<style:paragraph-properties fo:text-align="start" />
|
||||
<style:text-properties fo:color="#000000" fo:font-family="Calibri" fo:font-size="11.0pt" />
|
||||
</style:style>
|
||||
</office:automatic-styles>
|
||||
<office:body>
|
||||
<office:spreadsheet>
|
||||
<table:calculation-settings />
|
||||
<table:table table:name="Worksheet" table:style-name="ta1">
|
||||
<office:forms />
|
||||
<table:table-row>
|
||||
<table:table-cell office:value="1" office:value-type="float" table:style-name="ce0">
|
||||
<text:p>1</text:p>
|
||||
</table:table-cell>
|
||||
<table:table-cell table:number-columns-repeated="1023"/>
|
||||
</table:table-row>
|
||||
</table:table>
|
||||
<table:table table:name="New Worksheet" table:style-name="ta2">
|
||||
<office:forms/>
|
||||
<table:table-row>
|
||||
<table:table-cell office:value="2" office:value-type="float" table:style-name="ce0">
|
||||
<text:p>2</text:p>
|
||||
</table:table-cell>
|
||||
<table:table-cell table:number-columns-repeated="1023" />
|
||||
</table:table-row>
|
||||
</table:table>
|
||||
<table:named-expressions />
|
||||
</office:spreadsheet>
|
||||
</office:body>
|
||||
</office:document-content>
|
||||
|
|
@ -3,6 +3,12 @@
|
|||
<office:scripts/>
|
||||
<office:font-face-decls/>
|
||||
<office:automatic-styles>
|
||||
<style:style style:family="table" style:name="ta1">
|
||||
<style:table-properties table:display="true" />
|
||||
</style:style>
|
||||
<style:style style:family="table" style:name="ta2">
|
||||
<style:table-properties table:display="true" />
|
||||
</style:style>
|
||||
<style:style style:family="table-cell" style:name="ce0" style:parent-style-name="Default">
|
||||
<style:table-cell-properties style:rotation-align="none" style:vertical-align="bottom" />
|
||||
<style:paragraph-properties fo:text-align="start" />
|
||||
|
|
@ -62,7 +68,7 @@
|
|||
<office:body>
|
||||
<office:spreadsheet>
|
||||
<table:calculation-settings/>
|
||||
<table:table table:name="Worksheet">
|
||||
<table:table table:name="Worksheet" table:style-name="ta1">
|
||||
<office:forms/>
|
||||
<table:table-row>
|
||||
<table:table-cell office:value="1" office:value-type="float" table:style-name="ce2">
|
||||
|
|
@ -107,7 +113,7 @@
|
|||
<table:table-cell table:number-columns-repeated="1017"/>
|
||||
</table:table-row>
|
||||
</table:table>
|
||||
<table:table table:name="New Worksheet">
|
||||
<table:table table:name="New Worksheet" table:style-name="ta2">
|
||||
<office:forms/>
|
||||
<table:table-row>
|
||||
<table:table-cell office:value="2" office:value-type="float" table:style-name="ce0">
|
||||
|
|
|
|||
Loading…
Reference in New Issue