validation-bugsnag-email
This commit is contained in:
32
vendor/phpoffice/phpspreadsheet/CHANGELOG.md
vendored
32
vendor/phpoffice/phpspreadsheet/CHANGELOG.md
vendored
@@ -5,6 +5,38 @@ All notable changes to this project will be documented in this file.
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com)
|
||||
and this project adheres to [Semantic Versioning](https://semver.org).
|
||||
|
||||
## 1.27.0 - 2023-01-24
|
||||
|
||||
### Added
|
||||
|
||||
- Option to specify a range of columns/rows for the Row/Column `isEmpty()` methods [PR #3315](https://github.com/PHPOffice/PhpSpreadsheet/pull/3315)
|
||||
- Option for Cell Iterator to return a null value or create and return a new cell when accessing a cell that doesn't exist [PR #3314](https://github.com/PHPOffice/PhpSpreadsheet/pull/3314)
|
||||
- Support for Structured References in the Calculation Engine [PR #3261](https://github.com/PHPOffice/PhpSpreadsheet/pull/3261)
|
||||
- Limited Support for Form Controls [PR #3130](https://github.com/PHPOffice/PhpSpreadsheet/pull/3130) [Issue #2396](https://github.com/PHPOffice/PhpSpreadsheet/issues/2396) [Issue #1770](https://github.com/PHPOffice/PhpSpreadsheet/issues/1770) [Issue #2388](https://github.com/PHPOffice/PhpSpreadsheet/issues/2388) [Issue #2904](https://github.com/PHPOffice/PhpSpreadsheet/issues/2904) [Issue #2661](https://github.com/PHPOffice/PhpSpreadsheet/issues/2661)
|
||||
|
||||
### Changed
|
||||
|
||||
- Nothing
|
||||
|
||||
### Deprecated
|
||||
|
||||
- Nothing
|
||||
|
||||
### Removed
|
||||
|
||||
- Shared/JAMA is removed. [PR #3260](https://github.com/PHPOffice/PhpSpreadsheet/pull/3260)
|
||||
|
||||
### Fixed
|
||||
|
||||
- Namespace-Aware Code for SheetViewOptions, SheetProtection [PR #3230](https://github.com/PHPOffice/PhpSpreadsheet/pull/3230)
|
||||
- Additional Method for XIRR if Newton-Raphson Doesn't Converge [Issue #689](https://github.com/PHPOffice/PhpSpreadsheet/issues/689) [PR #3262](https://github.com/PHPOffice/PhpSpreadsheet/pull/3262)
|
||||
- Better Handling of Composite Charts [Issue #2333](https://github.com/PHPOffice/PhpSpreadsheet/issues/2333) [PR #3265](https://github.com/PHPOffice/PhpSpreadsheet/pull/3265)
|
||||
- Update Column Reference for Columns Beginning with Y and Z [Issue #3263](https://github.com/PHPOffice/PhpSpreadsheet/issues/3263) [PR #3264](https://github.com/PHPOffice/PhpSpreadsheet/pull/3264)
|
||||
- Honor Fit to 1-Page Height Html/Pdf [Issue #3266](https://github.com/PHPOffice/PhpSpreadsheet/issues/3266) [PR #3279](https://github.com/PHPOffice/PhpSpreadsheet/pull/3279)
|
||||
- AND/OR/XOR Handling of Literal Strings [PR #3287](https://github.com/PHPOffice/PhpSpreadsheet/pull/3287)
|
||||
- Xls Reader Vertical Break and Writer Page Order [Issue #3305](https://github.com/PHPOffice/PhpSpreadsheet/issues/3305) [PR #3306](https://github.com/PHPOffice/PhpSpreadsheet/pull/3306)
|
||||
|
||||
|
||||
## 1.26.0 - 2022-12-21
|
||||
|
||||
### Added
|
||||
|
27
vendor/phpoffice/phpspreadsheet/README.md
vendored
27
vendor/phpoffice/phpspreadsheet/README.md
vendored
@@ -91,6 +91,33 @@ Read more about it, including install instructions, in the [official documentati
|
||||
|
||||
Please ask your support questions on [StackOverflow](https://stackoverflow.com/questions/tagged/phpspreadsheet), or have a quick chat on [Gitter](https://gitter.im/PHPOffice/PhpSpreadsheet).
|
||||
|
||||
## Patreon
|
||||
|
||||
I am now running a [Patreon](https://www.patreon.com/MarkBaker) to support the work that I do on PhpSpreadsheet.
|
||||
|
||||
Supporters will receive access to articles about working with PhpSpreadsheet, and how to use some of its more advanced features.
|
||||
|
||||
Posts already available to Patreon supporters:
|
||||
- The Dating Game
|
||||
- A look at how MS Excel (and PhpSpreadsheet) handle date and time values.
|
||||
|
||||
The next post (currently being written) will be:
|
||||
- Looping the Loop
|
||||
- Advice on Iterating through the cells in a worksheet.
|
||||
|
||||
My aim is to post at least one article each month, taking a detailed look at some feature of MS Excel and how to use that feature in PhpSpreadsheet, or on how to perform different activities in PhpSpreadsheet.
|
||||
|
||||
Planned posts for the future include topics like:
|
||||
- Tables
|
||||
- Structured References
|
||||
- Array Formulae
|
||||
- Conditional Formatting
|
||||
- Data Validation
|
||||
- Formula Debugging
|
||||
- Value Binders
|
||||
|
||||
After a period of six months exclusive to Patreon supporters, articles will be incorporated into the public documentation for the library.
|
||||
|
||||
## PHPExcel vs PhpSpreadsheet ?
|
||||
|
||||
PhpSpreadsheet is the next version of PHPExcel. It breaks compatibility to dramatically improve the code base quality (namespaces, PSR compliance, use of latest PHP language features, etc.).
|
||||
|
@@ -1,195 +1,5 @@
|
||||
parameters:
|
||||
ignoreErrors:
|
||||
-
|
||||
message: "#^Variable \\$dateValue on left side of \\?\\? always exists and is not nullable\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Calculation/DateTimeExcel/DateValue.php
|
||||
|
||||
-
|
||||
message: "#^Variable \\$timeValue on left side of \\?\\? always exists and is not nullable\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Calculation/DateTimeExcel/TimeValue.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Engineering\\\\BesselJ\\:\\:besselj2a\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Calculation/Engineering/BesselJ.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Engineering\\\\BesselJ\\:\\:besselj2b\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Calculation/Engineering/BesselJ.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Engineering\\\\ConvertBase\\:\\:validatePlaces\\(\\) has parameter \\$places with no type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Calculation/Engineering/ConvertBase.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Engineering\\\\ConvertBase\\:\\:validateValue\\(\\) has parameter \\$value with no type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Calculation/Engineering/ConvertBase.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Engineering\\\\ConvertUOM\\:\\:getUOMDetails\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Calculation/Engineering/ConvertUOM.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Engineering\\\\ConvertUOM\\:\\:resolveTemperatureSynonyms\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Calculation/Engineering/ConvertUOM.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Engineering\\\\Erf\\:\\:erfValue\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Calculation/Engineering/Erf.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Engineering\\\\Erf\\:\\:erfValue\\(\\) has parameter \\$value with no type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Calculation/Engineering/Erf.php
|
||||
|
||||
-
|
||||
message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Engineering\\\\Erf\\:\\:\\$twoSqrtPi has no type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Calculation/Engineering/Erf.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Engineering\\\\ErfC\\:\\:erfcValue\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Calculation/Engineering/ErfC.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Engineering\\\\ErfC\\:\\:erfcValue\\(\\) has parameter \\$value with no type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Calculation/Engineering/ErfC.php
|
||||
|
||||
-
|
||||
message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Engineering\\\\ErfC\\:\\:\\$oneSqrtPi has no type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Calculation/Engineering/ErfC.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#1 \\$year of static method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\DateTimeExcel\\\\Helpers\\:\\:isLeapYear\\(\\) expects int\\|string, array\\|int\\|string given\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Calculation/Financial/Amortization.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\CashFlow\\\\Constant\\\\Periodic\\\\Interest\\:\\:rateNextGuess\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic/Interest.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\CashFlow\\\\Constant\\\\Periodic\\\\Interest\\:\\:rateNextGuess\\(\\) has parameter \\$futureValue with no type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic/Interest.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\CashFlow\\\\Constant\\\\Periodic\\\\Interest\\:\\:rateNextGuess\\(\\) has parameter \\$numberOfPeriods with no type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic/Interest.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\CashFlow\\\\Constant\\\\Periodic\\\\Interest\\:\\:rateNextGuess\\(\\) has parameter \\$payment with no type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic/Interest.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\CashFlow\\\\Constant\\\\Periodic\\\\Interest\\:\\:rateNextGuess\\(\\) has parameter \\$presentValue with no type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic/Interest.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\CashFlow\\\\Constant\\\\Periodic\\\\Interest\\:\\:rateNextGuess\\(\\) has parameter \\$rate with no type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic/Interest.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\CashFlow\\\\Constant\\\\Periodic\\\\Interest\\:\\:rateNextGuess\\(\\) has parameter \\$type with no type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic/Interest.php
|
||||
|
||||
-
|
||||
message: "#^Binary operation \"\\-\" between float\\|string and 0\\|float results in an error\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic/InterestAndPrincipal.php
|
||||
|
||||
-
|
||||
message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\CashFlow\\\\Constant\\\\Periodic\\\\InterestAndPrincipal\\:\\:\\$interest has no type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic/InterestAndPrincipal.php
|
||||
|
||||
-
|
||||
message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\CashFlow\\\\Constant\\\\Periodic\\\\InterestAndPrincipal\\:\\:\\$principal has no type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic/InterestAndPrincipal.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\CashFlow\\\\Variable\\\\NonPeriodic\\:\\:xnpvOrdered\\(\\) should return float\\|string but returns array\\|string\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Variable/NonPeriodic.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\CashFlow\\\\Variable\\\\Periodic\\:\\:presentValue\\(\\) has parameter \\$args with no type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Variable/Periodic.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#1 \\$year of static method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Helpers\\:\\:daysPerYear\\(\\) expects int\\|string, array\\|int\\|string given\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Calculation/Financial/Coupons.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Depreciation\\:\\:validateCost\\(\\) has parameter \\$cost with no type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Calculation/Financial/Depreciation.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Depreciation\\:\\:validateFactor\\(\\) has parameter \\$factor with no type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Calculation/Financial/Depreciation.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Depreciation\\:\\:validateLife\\(\\) has parameter \\$life with no type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Calculation/Financial/Depreciation.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Depreciation\\:\\:validateMonth\\(\\) has parameter \\$month with no type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Calculation/Financial/Depreciation.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Depreciation\\:\\:validatePeriod\\(\\) has parameter \\$period with no type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Calculation/Financial/Depreciation.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Depreciation\\:\\:validateSalvage\\(\\) has parameter \\$salvage with no type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Calculation/Financial/Depreciation.php
|
||||
|
||||
-
|
||||
message: "#^Binary operation \"/\" between float\\|string and float\\|string results in an error\\.$#"
|
||||
count: 2
|
||||
path: src/PhpSpreadsheet/Calculation/Financial/Securities/Price.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Securities\\\\Price\\:\\:received\\(\\) should return float\\|string but returns array\\|string\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Calculation/Financial/Securities/Price.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#1 \\$year of static method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Helpers\\:\\:daysPerYear\\(\\) expects int\\|string, array\\|int\\|string given\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Calculation/Financial/Securities/Price.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#1 \\$year of static method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Helpers\\:\\:daysPerYear\\(\\) expects int\\|string, array\\|int\\|string given\\.$#"
|
||||
count: 2
|
||||
path: src/PhpSpreadsheet/Calculation/Financial/Securities/Yields.php
|
||||
|
||||
-
|
||||
message: "#^Cannot call method getTokenSubType\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\FormulaToken\\|null\\.$#"
|
||||
count: 4
|
||||
@@ -215,71 +25,6 @@ parameters:
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Calculation/FormulaParser.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Functions\\:\\:ifCondition\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Calculation/Functions.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Functions\\:\\:ifCondition\\(\\) has parameter \\$condition with no type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Calculation/Functions.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Functions\\:\\:isCellValue\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Calculation/Functions.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Functions\\:\\:isCellValue\\(\\) has parameter \\$idx with no type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Calculation/Functions.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Functions\\:\\:isMatrixValue\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Calculation/Functions.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Functions\\:\\:isMatrixValue\\(\\) has parameter \\$idx with no type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Calculation/Functions.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Functions\\:\\:isValue\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Calculation/Functions.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Functions\\:\\:isValue\\(\\) has parameter \\$idx with no type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Calculation/Functions.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Functions\\:\\:operandSpecialHandling\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Calculation/Functions.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Functions\\:\\:operandSpecialHandling\\(\\) has parameter \\$operand with no type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Calculation/Functions.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Internal\\\\MakeMatrix\\:\\:make\\(\\) has parameter \\$args with no type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Calculation/Internal/MakeMatrix.php
|
||||
|
||||
-
|
||||
message: "#^Call to function is_string\\(\\) with null will always evaluate to false\\.$#"
|
||||
count: 3
|
||||
path: src/PhpSpreadsheet/Calculation/Logical/Operations.php
|
||||
|
||||
-
|
||||
message: "#^Result of && is always false\\.$#"
|
||||
count: 3
|
||||
path: src/PhpSpreadsheet/Calculation/Logical/Operations.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\LookupRef\\:\\:CHOOSE\\(\\) has parameter \\$chooseArgs with no type specified\\.$#"
|
||||
count: 1
|
||||
@@ -355,266 +100,6 @@ parameters:
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Calculation/LookupRef/Offset.php
|
||||
|
||||
-
|
||||
message: "#^Binary operation \"/\" between array\\|float\\|int\\|string and array\\|float\\|int\\|string results in an error\\.$#"
|
||||
count: 2
|
||||
path: src/PhpSpreadsheet/Calculation/MathTrig/Combinations.php
|
||||
|
||||
-
|
||||
message: "#^Binary operation \"/\" between array\\|float\\|int\\|string and float\\|int results in an error\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Calculation/MathTrig/Factorial.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\MathTrig\\\\IntClass\\:\\:evaluate\\(\\) should return array\\|string but returns int\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Calculation/MathTrig/IntClass.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\:\\:MAXIFS\\(\\) should return float but returns float\\|string\\|null\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Calculation/Statistical.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\:\\:MINIFS\\(\\) should return float but returns float\\|string\\|null\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Calculation/Statistical.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Averages\\:\\:filterArguments\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Calculation/Statistical/Averages.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Averages\\:\\:filterArguments\\(\\) has parameter \\$args with no type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Calculation/Statistical/Averages.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Averages\\:\\:modeCalc\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Calculation/Statistical/Averages.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Averages\\:\\:modeCalc\\(\\) has parameter \\$data with no type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Calculation/Statistical/Averages.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Conditional\\:\\:SUMIF\\(\\) should return float\\|string but returns float\\|string\\|null\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Calculation/Statistical/Conditional.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Conditional\\:\\:buildConditionSet\\(\\) has parameter \\$args with no type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Calculation/Statistical/Conditional.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Conditional\\:\\:buildConditionSetForValueRange\\(\\) has parameter \\$args with no type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Calculation/Statistical/Conditional.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Conditional\\:\\:buildConditions\\(\\) has parameter \\$args with no type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Calculation/Statistical/Conditional.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Conditional\\:\\:buildDataSet\\(\\) has parameter \\$args with no type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Calculation/Statistical/Conditional.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Conditional\\:\\:buildDatabase\\(\\) has parameter \\$args with no type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Calculation/Statistical/Conditional.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Conditional\\:\\:buildDatabaseWithValueRange\\(\\) has parameter \\$args with no type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Calculation/Statistical/Conditional.php
|
||||
|
||||
-
|
||||
message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\Beta\\:\\:\\$logBetaCacheP has no type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/Beta.php
|
||||
|
||||
-
|
||||
message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\Beta\\:\\:\\$logBetaCacheQ has no type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/Beta.php
|
||||
|
||||
-
|
||||
message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\Beta\\:\\:\\$logBetaCacheResult has no type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/Beta.php
|
||||
|
||||
-
|
||||
message: "#^Constant PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\ChiSquared\\:\\:MAX_ITERATIONS is unused\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/ChiSquared.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\ChiSquared\\:\\:gammp\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/ChiSquared.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\ChiSquared\\:\\:gammp\\(\\) has parameter \\$n with no type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/ChiSquared.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\ChiSquared\\:\\:gammp\\(\\) has parameter \\$x with no type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/ChiSquared.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\ChiSquared\\:\\:gcf\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/ChiSquared.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\ChiSquared\\:\\:gcf\\(\\) has parameter \\$n with no type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/ChiSquared.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\ChiSquared\\:\\:gcf\\(\\) has parameter \\$x with no type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/ChiSquared.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\ChiSquared\\:\\:gser\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/ChiSquared.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\ChiSquared\\:\\:gser\\(\\) has parameter \\$n with no type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/ChiSquared.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\ChiSquared\\:\\:gser\\(\\) has parameter \\$x with no type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/ChiSquared.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\ChiSquared\\:\\:pchisq\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/ChiSquared.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\ChiSquared\\:\\:pchisq\\(\\) has parameter \\$chi2 with no type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/ChiSquared.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\ChiSquared\\:\\:pchisq\\(\\) has parameter \\$degrees with no type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/ChiSquared.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#2 \\$columns of static method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\ChiSquared\\:\\:degrees\\(\\) expects int, float\\|int\\<0, max\\> given\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/ChiSquared.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\GammaBase\\:\\:calculateDistribution\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/GammaBase.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\GammaBase\\:\\:calculateInverse\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/GammaBase.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\GammaBase\\:\\:logGamma1\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/GammaBase.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\GammaBase\\:\\:logGamma2\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/GammaBase.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\GammaBase\\:\\:logGamma3\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/GammaBase.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\GammaBase\\:\\:logGamma4\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/GammaBase.php
|
||||
|
||||
-
|
||||
message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\GammaBase\\:\\:\\$logGammaCacheResult has no type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/GammaBase.php
|
||||
|
||||
-
|
||||
message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\GammaBase\\:\\:\\$logGammaCacheX has no type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/GammaBase.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\NewtonRaphson\\:\\:execute\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/NewtonRaphson.php
|
||||
|
||||
-
|
||||
message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\NewtonRaphson\\:\\:\\$callback has no type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/NewtonRaphson.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\Normal\\:\\:inverseNcdf\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/Normal.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\Normal\\:\\:inverseNcdf\\(\\) has parameter \\$p with no type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/Normal.php
|
||||
|
||||
-
|
||||
message: "#^Binary operation \"\\-\" between float\\|string and float\\|int\\|numeric\\-string results in an error\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/StandardNormal.php
|
||||
|
||||
-
|
||||
message: "#^Constant PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\StudentT\\:\\:MAX_ITERATIONS is unused\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/StudentT.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\MaxMinBase\\:\\:datatypeAdjustmentAllowStrings\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Calculation/Statistical/MaxMinBase.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\MaxMinBase\\:\\:datatypeAdjustmentAllowStrings\\(\\) has parameter \\$value with no type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Calculation/Statistical/MaxMinBase.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Percentiles\\:\\:percentileFilterValues\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Calculation/Statistical/Percentiles.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Percentiles\\:\\:rankFilterValues\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Calculation/Statistical/Percentiles.php
|
||||
|
||||
-
|
||||
message: "#^Binary operation \"/\" between array\\|float\\|int\\|string and array\\|float\\|int\\|string results in an error\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Calculation/Statistical/Permutations.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Trends\\:\\:GROWTH\\(\\) should return array\\<float\\> but returns array\\<int, array\\<int, array\\<int, mixed\\>\\>\\>\\.$#"
|
||||
count: 1
|
||||
@@ -635,26 +120,6 @@ parameters:
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Calculation/Statistical/Trends.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\VarianceBase\\:\\:datatypeAdjustmentAllowStrings\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Calculation/Statistical/VarianceBase.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\VarianceBase\\:\\:datatypeAdjustmentAllowStrings\\(\\) has parameter \\$value with no type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Calculation/Statistical/VarianceBase.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\VarianceBase\\:\\:datatypeAdjustmentBooleans\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Calculation/Statistical/VarianceBase.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\VarianceBase\\:\\:datatypeAdjustmentBooleans\\(\\) has parameter \\$value with no type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Calculation/Statistical/VarianceBase.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\TextData\\:\\:CONCATENATE\\(\\) has parameter \\$args with no type specified\\.$#"
|
||||
count: 1
|
||||
@@ -685,21 +150,6 @@ parameters:
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Cell/Coordinate.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#1 \\$namedRange of method PhpOffice\\\\PhpSpreadsheet\\\\Spreadsheet\\:\\:addNamedRange\\(\\) expects PhpOffice\\\\PhpSpreadsheet\\\\NamedRange, \\$this\\(PhpOffice\\\\PhpSpreadsheet\\\\DefinedName\\) given\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/DefinedName.php
|
||||
|
||||
-
|
||||
message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\DefinedName\\:\\:\\$scope \\(PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Worksheet\\) does not accept PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Worksheet\\|null\\.$#"
|
||||
count: 3
|
||||
path: src/PhpSpreadsheet/DefinedName.php
|
||||
|
||||
-
|
||||
message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\DefinedName\\:\\:\\$worksheet \\(PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Worksheet\\) does not accept PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Worksheet\\|null\\.$#"
|
||||
count: 2
|
||||
path: src/PhpSpreadsheet/DefinedName.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\IOFactory\\:\\:createReader\\(\\) should return PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\IReader but returns object\\.$#"
|
||||
count: 1
|
||||
@@ -1120,91 +570,6 @@ parameters:
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Shared/Escher/DggContainer/BstoreContainer/BSE.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\JAMA\\\\Matrix\\:\\:__construct\\(\\) has parameter \\$args with no type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Shared/JAMA/Matrix.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\JAMA\\\\Matrix\\:\\:arrayLeftDivide\\(\\) has parameter \\$args with no type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Shared/JAMA/Matrix.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\JAMA\\\\Matrix\\:\\:arrayLeftDivideEquals\\(\\) has parameter \\$args with no type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Shared/JAMA/Matrix.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\JAMA\\\\Matrix\\:\\:arrayRightDivide\\(\\) has parameter \\$args with no type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Shared/JAMA/Matrix.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\JAMA\\\\Matrix\\:\\:arrayRightDivideEquals\\(\\) has parameter \\$args with no type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Shared/JAMA/Matrix.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\JAMA\\\\Matrix\\:\\:arrayTimes\\(\\) has parameter \\$args with no type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Shared/JAMA/Matrix.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\JAMA\\\\Matrix\\:\\:arrayTimesEquals\\(\\) has parameter \\$args with no type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Shared/JAMA/Matrix.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\JAMA\\\\Matrix\\:\\:concat\\(\\) has parameter \\$args with no type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Shared/JAMA/Matrix.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\JAMA\\\\Matrix\\:\\:getMatrix\\(\\) has parameter \\$args with no type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Shared/JAMA/Matrix.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\JAMA\\\\Matrix\\:\\:minus\\(\\) has parameter \\$args with no type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Shared/JAMA/Matrix.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\JAMA\\\\Matrix\\:\\:minusEquals\\(\\) has parameter \\$args with no type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Shared/JAMA/Matrix.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\JAMA\\\\Matrix\\:\\:plus\\(\\) has parameter \\$args with no type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Shared/JAMA/Matrix.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\JAMA\\\\Matrix\\:\\:plusEquals\\(\\) has parameter \\$args with no type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Shared/JAMA/Matrix.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\JAMA\\\\Matrix\\:\\:power\\(\\) has parameter \\$args with no type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Shared/JAMA/Matrix.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\JAMA\\\\Matrix\\:\\:times\\(\\) has parameter \\$args with no type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Shared/JAMA/Matrix.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#3 \\$c of method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\JAMA\\\\Matrix\\:\\:set\\(\\) expects float\\|int\\|null, string given\\.$#"
|
||||
count: 2
|
||||
path: src/PhpSpreadsheet/Shared/JAMA/Matrix.php
|
||||
|
||||
-
|
||||
message: "#^Unreachable statement \\- code above always terminates\\.$#"
|
||||
count: 14
|
||||
path: src/PhpSpreadsheet/Shared/JAMA/Matrix.php
|
||||
|
||||
-
|
||||
message: "#^Cannot access offset 1 on array\\|false\\.$#"
|
||||
count: 1
|
||||
@@ -1760,101 +1125,6 @@ parameters:
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Style/NumberFormat/PercentageFormatter.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\CellIterator\\:\\:adjustForExistingOnlyRange\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Worksheet/CellIterator.php
|
||||
|
||||
-
|
||||
message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Drawing\\\\Shadow\\:\\:\\$color \\(PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Color\\) does not accept PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Color\\|null\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Worksheet/Drawing/Shadow.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\PageSetup\\:\\:getPrintArea\\(\\) should return string but returns string\\|null\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Worksheet/PageSetup.php
|
||||
|
||||
-
|
||||
message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Worksheet/Worksheet.php
|
||||
|
||||
-
|
||||
message: "#^Cannot call method getHashCode\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Worksheet\\|null\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Worksheet/Worksheet.php
|
||||
|
||||
-
|
||||
message: "#^Cannot call method getValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#"
|
||||
count: 4
|
||||
path: src/PhpSpreadsheet/Worksheet/Worksheet.php
|
||||
|
||||
-
|
||||
message: "#^Cannot call method getWorksheet\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\DefinedName\\|null\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Worksheet/Worksheet.php
|
||||
|
||||
-
|
||||
message: "#^Cannot call method getXfIndex\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Worksheet/Worksheet.php
|
||||
|
||||
-
|
||||
message: "#^Cannot call method rangeToArray\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Worksheet\\|null\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Worksheet/Worksheet.php
|
||||
|
||||
-
|
||||
message: "#^If condition is always true\\.$#"
|
||||
count: 2
|
||||
path: src/PhpSpreadsheet/Worksheet/Worksheet.php
|
||||
|
||||
-
|
||||
message: "#^Left side of && is always true\\.$#"
|
||||
count: 2
|
||||
path: src/PhpSpreadsheet/Worksheet/Worksheet.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Worksheet\\:\\:getChartByName\\(\\) should return PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Chart\\|false but returns PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Chart\\|null\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Worksheet/Worksheet.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#1 \\$index of class PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\ColumnDimension constructor expects string, null given\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Worksheet/Worksheet.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#1 \\$index of class PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\RowDimension constructor expects int, null given\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Worksheet/Worksheet.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#1 \\$range of static method PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Coordinate\\:\\:rangeDimension\\(\\) expects string, string\\|false given\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Worksheet/Worksheet.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#2 \\$format of static method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\NumberFormat\\:\\:toFormattedString\\(\\) expects string, string\\|null given\\.$#"
|
||||
count: 2
|
||||
path: src/PhpSpreadsheet/Worksheet/Worksheet.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#3 \\$rotation of static method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Font\\:\\:calculateColumnWidth\\(\\) expects int, int\\|null given\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Worksheet/Worksheet.php
|
||||
|
||||
-
|
||||
message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Worksheet\\:\\:\\$parent \\(PhpOffice\\\\PhpSpreadsheet\\\\Spreadsheet\\) does not accept PhpOffice\\\\PhpSpreadsheet\\\\Spreadsheet\\|null\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Worksheet/Worksheet.php
|
||||
|
||||
-
|
||||
message: "#^Right side of && is always true\\.$#"
|
||||
count: 1
|
||||
path: src/PhpSpreadsheet/Worksheet/Worksheet.php
|
||||
|
||||
-
|
||||
message: "#^Negated boolean expression is always false\\.$#"
|
||||
count: 1
|
||||
|
@@ -74,11 +74,6 @@ if (PHP_VERSION_ID < 80000) {
|
||||
'path' => __DIR__ . '/src/PhpSpreadsheet/Calculation/TextData/Text.php',
|
||||
'count' => 1,
|
||||
];
|
||||
$config['parameters']['ignoreErrors'][] = [
|
||||
'message' => '#^Property PhpOffice\\PhpSpreadsheet\\Shared\\JAMA\\Matrix::$A (array) does not accept array<int, array<int, int>|false>|false.$#',
|
||||
'path' => __DIR__ . '/src/PhpSpreadsheet/Shared/JAMA/Matrix.php',
|
||||
'count' => 2,
|
||||
];
|
||||
} else {
|
||||
// Flagged in Php8+ - unsure how to correct code
|
||||
$config['parameters']['ignoreErrors'][] = [
|
||||
|
@@ -6,8 +6,6 @@ use PhpOffice\PhpSpreadsheet\Calculation\Engine\BranchPruner;
|
||||
use PhpOffice\PhpSpreadsheet\Calculation\Engine\CyclicReferenceStack;
|
||||
use PhpOffice\PhpSpreadsheet\Calculation\Engine\Logger;
|
||||
use PhpOffice\PhpSpreadsheet\Calculation\Engine\Operands;
|
||||
use PhpOffice\PhpSpreadsheet\Calculation\Information\ErrorValue;
|
||||
use PhpOffice\PhpSpreadsheet\Calculation\Information\ExcelError;
|
||||
use PhpOffice\PhpSpreadsheet\Calculation\Token\Stack;
|
||||
use PhpOffice\PhpSpreadsheet\Cell\AddressRange;
|
||||
use PhpOffice\PhpSpreadsheet\Cell\Cell;
|
||||
@@ -4452,7 +4450,7 @@ class Calculation
|
||||
|
||||
$refSheet = $pCellParent;
|
||||
if ($pCellParent !== null && $rangeSheetRef !== '' && $rangeSheetRef !== $pCellParent->getTitle()) {
|
||||
$refSheet = $pCellParent->getParent()->getSheetByName($rangeSheetRef);
|
||||
$refSheet = $pCellParent->getParentOrThrow()->getSheetByName($rangeSheetRef);
|
||||
}
|
||||
|
||||
if (ctype_digit($val) && $val <= 1048576) {
|
||||
@@ -4632,14 +4630,6 @@ class Calculation
|
||||
return $operand;
|
||||
}
|
||||
|
||||
private const NUMERIC_BINARY_OPERATIONS = [
|
||||
'+' => 'plusEquals',
|
||||
'-' => 'minusEquals',
|
||||
'*' => 'arrayTimesEquals',
|
||||
'/' => 'arrayRightDivide',
|
||||
'^' => 'power',
|
||||
];
|
||||
|
||||
/**
|
||||
* @param mixed $tokens
|
||||
* @param null|string $cellID
|
||||
@@ -4679,7 +4669,7 @@ class Calculation
|
||||
|
||||
if (
|
||||
(isset($storeValue) || $tokenData['reference'] === 'NULL')
|
||||
&& (!$storeValueAsBool || ErrorValue::isError($storeValue) || ($storeValue === 'Pruned branch'))
|
||||
&& (!$storeValueAsBool || Information\ErrorValue::isError($storeValue) || ($storeValue === 'Pruned branch'))
|
||||
) {
|
||||
// If branching value is not true, we don't need to compute
|
||||
if (!isset($fakedForBranchPruning['onlyIf-' . $onlyIfStoreKey])) {
|
||||
@@ -4711,7 +4701,7 @@ class Calculation
|
||||
|
||||
if (
|
||||
(isset($storeValue) || $tokenData['reference'] === 'NULL')
|
||||
&& ($storeValueAsBool || ErrorValue::isError($storeValue) || ($storeValue === 'Pruned branch'))
|
||||
&& ($storeValueAsBool || Information\ErrorValue::isError($storeValue) || ($storeValue === 'Pruned branch'))
|
||||
) {
|
||||
// If branching value is true, we don't need to compute
|
||||
if (!isset($fakedForBranchPruning['onlyIfNot-' . $onlyIfNotStoreKey])) {
|
||||
@@ -4732,13 +4722,33 @@ class Calculation
|
||||
}
|
||||
|
||||
if ($token instanceof Operands\StructuredReference) {
|
||||
throw new Exception('Structured References are not currently supported');
|
||||
// The next step is converting any structured reference to a cell value of range
|
||||
// to a new $token value, which can then be processed in the following code.
|
||||
}
|
||||
if ($cell === null) {
|
||||
return $this->raiseFormulaError('Structured References must exist in a Cell context');
|
||||
}
|
||||
|
||||
// if the token is a binary operator, pop the top two values off the stack, do the operation, and push the result back on the stack
|
||||
if (!is_numeric($token) && !is_object($token) && isset(self::BINARY_OPERATORS[$token])) {
|
||||
try {
|
||||
$cellRange = $token->parse($cell);
|
||||
if (strpos($cellRange, ':') !== false) {
|
||||
$this->debugLog->writeDebugLog('Evaluating Structured Reference %s as Cell Range %s', $token->value(), $cellRange);
|
||||
$rangeValue = self::getInstance($cell->getWorksheet()->getParent())->_calculateFormulaValue("={$cellRange}", $token->value(), $cell);
|
||||
$stack->push('Value', $rangeValue);
|
||||
$this->debugLog->writeDebugLog('Evaluated Structured Reference %s as value %s', $token->value(), $this->showValue($rangeValue));
|
||||
} else {
|
||||
$this->debugLog->writeDebugLog('Evaluating Structured Reference %s as Cell %s', $token->value(), $cellRange);
|
||||
$cellValue = $cell->getWorksheet()->getCell($cellRange)->getCalculatedValue(false);
|
||||
$stack->push('Cell Reference', $cellValue, $cellRange);
|
||||
$this->debugLog->writeDebugLog('Evaluated Structured Reference %s as value %s', $token->value(), $this->showValue($cellValue));
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
if ($e->getCode() === Exception::CALCULATION_ENGINE_PUSH_TO_STACK) {
|
||||
$stack->push('Error', Information\ExcelError::REF(), null);
|
||||
$this->debugLog->writeDebugLog('Evaluated Structured Reference %s as error value %s', $token->value(), Information\ExcelError::REF());
|
||||
} else {
|
||||
return $this->raiseFormulaError($e->getMessage());
|
||||
}
|
||||
}
|
||||
} elseif (!is_numeric($token) && !is_object($token) && isset(self::BINARY_OPERATORS[$token])) {
|
||||
// if the token is a binary operator, pop the top two values off the stack, do the operation, and push the result back on the stack
|
||||
// We must have two operands, error if we don't
|
||||
if (($operand2Data = $stack->pop()) === null) {
|
||||
return $this->raiseFormulaError('Internal error - Operand value missing from stack');
|
||||
@@ -4842,7 +4852,7 @@ class Calculation
|
||||
case '*': // Multiplication
|
||||
case '/': // Division
|
||||
case '^': // Exponential
|
||||
$result = $this->executeNumericBinaryOperation($operand1, $operand2, $token, self::NUMERIC_BINARY_OPERATIONS[$token], $stack);
|
||||
$result = $this->executeNumericBinaryOperation($operand1, $operand2, $token, $stack);
|
||||
if (isset($storeKey)) {
|
||||
$branchStore[$storeKey] = $result;
|
||||
}
|
||||
@@ -4852,29 +4862,30 @@ class Calculation
|
||||
// If either of the operands is a matrix, we need to treat them both as matrices
|
||||
// (converting the other operand to a matrix if need be); then perform the required
|
||||
// matrix operation
|
||||
if (is_bool($operand1)) {
|
||||
$operand1 = ($operand1) ? self::$localeBoolean['TRUE'] : self::$localeBoolean['FALSE'];
|
||||
}
|
||||
if (is_bool($operand2)) {
|
||||
$operand2 = ($operand2) ? self::$localeBoolean['TRUE'] : self::$localeBoolean['FALSE'];
|
||||
}
|
||||
if ((is_array($operand1)) || (is_array($operand2))) {
|
||||
// Ensure that both operands are arrays/matrices
|
||||
self::checkMatrixOperands($operand1, $operand2, 2);
|
||||
|
||||
try {
|
||||
// Convert operand 1 from a PHP array to a matrix
|
||||
$matrix = new Shared\JAMA\Matrix($operand1);
|
||||
// Perform the required operation against the operand 1 matrix, passing in operand 2
|
||||
$matrixResult = $matrix->concat($operand2);
|
||||
$result = $matrixResult->getArray();
|
||||
if (isset($result[0][0])) {
|
||||
$result[0][0] = Shared\StringHelper::substring($result[0][0], 0, DataType::MAX_STRING_LENGTH);
|
||||
}
|
||||
} catch (\Exception $ex) {
|
||||
$this->debugLog->writeDebugLog('JAMA Matrix Exception: %s', $ex->getMessage());
|
||||
$result = '#VALUE!';
|
||||
$operand1 = self::boolToString($operand1);
|
||||
$operand2 = self::boolToString($operand2);
|
||||
if (is_array($operand1) || is_array($operand2)) {
|
||||
if (is_string($operand1)) {
|
||||
$operand1 = self::unwrapResult($operand1);
|
||||
}
|
||||
if (is_string($operand2)) {
|
||||
$operand2 = self::unwrapResult($operand2);
|
||||
}
|
||||
// Ensure that both operands are arrays/matrices
|
||||
[$rows, $columns] = self::checkMatrixOperands($operand1, $operand2, 2);
|
||||
|
||||
for ($row = 0; $row < $rows; ++$row) {
|
||||
for ($column = 0; $column < $columns; ++$column) {
|
||||
$operand1[$row][$column] =
|
||||
Shared\StringHelper::substring(
|
||||
self::boolToString($operand1[$row][$column])
|
||||
. self::boolToString($operand2[$row][$column]),
|
||||
0,
|
||||
DataType::MAX_STRING_LENGTH
|
||||
);
|
||||
}
|
||||
}
|
||||
$result = $operand1;
|
||||
} else {
|
||||
// In theory, we should truncate here.
|
||||
// But I can't figure out a formula
|
||||
@@ -4927,23 +4938,26 @@ class Calculation
|
||||
$multiplier = 0.01;
|
||||
}
|
||||
if (is_array($arg)) {
|
||||
self::checkMatrixOperands($arg, $multiplier, 2);
|
||||
|
||||
try {
|
||||
$matrix1 = new Shared\JAMA\Matrix($arg);
|
||||
$matrixResult = $matrix1->arrayTimesEquals($multiplier);
|
||||
$result = $matrixResult->getArray();
|
||||
} catch (\Exception $ex) {
|
||||
$this->debugLog->writeDebugLog('JAMA Matrix Exception: %s', $ex->getMessage());
|
||||
$result = '#VALUE!';
|
||||
$operand2 = $multiplier;
|
||||
$result = $arg;
|
||||
[$rows, $columns] = self::checkMatrixOperands($result, $operand2, 0);
|
||||
for ($row = 0; $row < $rows; ++$row) {
|
||||
for ($column = 0; $column < $columns; ++$column) {
|
||||
if (is_numeric($result[$row][$column])) {
|
||||
$result[$row][$column] *= $multiplier;
|
||||
} else {
|
||||
$result[$row][$column] = Information\ExcelError::VALUE();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$this->debugLog->writeDebugLog('Evaluation Result is %s', $this->showTypeDetails($result));
|
||||
$stack->push('Value', $result);
|
||||
if (isset($storeKey)) {
|
||||
$branchStore[$storeKey] = $result;
|
||||
}
|
||||
} else {
|
||||
$this->executeNumericBinaryOperation($multiplier, $arg, '*', 'arrayTimesEquals', $stack);
|
||||
$this->executeNumericBinaryOperation($multiplier, $arg, '*', $stack);
|
||||
}
|
||||
} elseif (preg_match('/^' . self::CALCULATION_REGEXP_CELLREF . '$/i', $token ?? '', $matches)) {
|
||||
$cellRef = null;
|
||||
@@ -5283,12 +5297,11 @@ class Calculation
|
||||
* @param mixed $operand1
|
||||
* @param mixed $operand2
|
||||
* @param string $operation
|
||||
* @param string $matrixFunction
|
||||
* @param Stack $stack
|
||||
*
|
||||
* @return bool|mixed
|
||||
*/
|
||||
private function executeNumericBinaryOperation($operand1, $operand2, $operation, $matrixFunction, &$stack)
|
||||
private function executeNumericBinaryOperation($operand1, $operand2, $operation, &$stack)
|
||||
{
|
||||
// Validate the two operands
|
||||
if (
|
||||
@@ -5298,70 +5311,113 @@ class Calculation
|
||||
return false;
|
||||
}
|
||||
|
||||
// If either of the operands is a matrix, we need to treat them both as matrices
|
||||
// (converting the other operand to a matrix if need be); then perform the required
|
||||
// matrix operation
|
||||
if ((is_array($operand1)) || (is_array($operand2))) {
|
||||
// Ensure that both operands are arrays/matrices of the same size
|
||||
self::checkMatrixOperands($operand1, $operand2, 2);
|
||||
|
||||
try {
|
||||
// Convert operand 1 from a PHP array to a matrix
|
||||
$matrix = new Shared\JAMA\Matrix($operand1);
|
||||
// Perform the required operation against the operand 1 matrix, passing in operand 2
|
||||
$matrixResult = $matrix->$matrixFunction($operand2);
|
||||
$result = $matrixResult->getArray();
|
||||
} catch (\Exception $ex) {
|
||||
$this->debugLog->writeDebugLog('JAMA Matrix Exception: %s', $ex->getMessage());
|
||||
$result = '#VALUE!';
|
||||
}
|
||||
} else {
|
||||
if (
|
||||
(Functions::getCompatibilityMode() != Functions::COMPATIBILITY_OPENOFFICE) &&
|
||||
((is_string($operand1) && !is_numeric($operand1) && strlen($operand1) > 0) ||
|
||||
(is_string($operand2) && !is_numeric($operand2) && strlen($operand2) > 0))
|
||||
) {
|
||||
$result = Information\ExcelError::VALUE();
|
||||
} else {
|
||||
// If we're dealing with non-matrix operations, execute the necessary operation
|
||||
switch ($operation) {
|
||||
// Addition
|
||||
case '+':
|
||||
$result = $operand1 + $operand2;
|
||||
|
||||
break;
|
||||
// Subtraction
|
||||
case '-':
|
||||
$result = $operand1 - $operand2;
|
||||
|
||||
break;
|
||||
// Multiplication
|
||||
case '*':
|
||||
$result = $operand1 * $operand2;
|
||||
|
||||
break;
|
||||
// Division
|
||||
case '/':
|
||||
if ($operand2 == 0) {
|
||||
// Trap for Divide by Zero error
|
||||
$stack->push('Error', ExcelError::DIV0());
|
||||
$this->debugLog->writeDebugLog('Evaluation Result is %s', $this->showTypeDetails(ExcelError::DIV0()));
|
||||
|
||||
return false;
|
||||
}
|
||||
$result = $operand1 / $operand2;
|
||||
|
||||
break;
|
||||
// Power
|
||||
case '^':
|
||||
$result = $operand1 ** $operand2;
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new Exception('Unsupported numeric binary operation');
|
||||
if (
|
||||
(Functions::getCompatibilityMode() != Functions::COMPATIBILITY_OPENOFFICE) &&
|
||||
((is_string($operand1) && !is_numeric($operand1) && strlen($operand1) > 0) ||
|
||||
(is_string($operand2) && !is_numeric($operand2) && strlen($operand2) > 0))
|
||||
) {
|
||||
$result = Information\ExcelError::VALUE();
|
||||
} elseif (is_array($operand1) || is_array($operand2)) {
|
||||
// Ensure that both operands are arrays/matrices
|
||||
if (is_array($operand1)) {
|
||||
foreach ($operand1 as $key => $value) {
|
||||
$operand1[$key] = Functions::flattenArray($value);
|
||||
}
|
||||
}
|
||||
if (is_array($operand2)) {
|
||||
foreach ($operand2 as $key => $value) {
|
||||
$operand2[$key] = Functions::flattenArray($value);
|
||||
}
|
||||
}
|
||||
[$rows, $columns] = self::checkMatrixOperands($operand1, $operand2, 2);
|
||||
|
||||
for ($row = 0; $row < $rows; ++$row) {
|
||||
for ($column = 0; $column < $columns; ++$column) {
|
||||
if ($operand1[$row][$column] === null) {
|
||||
$operand1[$row][$column] = 0;
|
||||
} elseif (!is_numeric($operand1[$row][$column])) {
|
||||
$operand1[$row][$column] = Information\ExcelError::VALUE();
|
||||
|
||||
continue;
|
||||
}
|
||||
if ($operand2[$row][$column] === null) {
|
||||
$operand2[$row][$column] = 0;
|
||||
} elseif (!is_numeric($operand2[$row][$column])) {
|
||||
$operand1[$row][$column] = Information\ExcelError::VALUE();
|
||||
|
||||
continue;
|
||||
}
|
||||
switch ($operation) {
|
||||
case '+':
|
||||
$operand1[$row][$column] += $operand2[$row][$column];
|
||||
|
||||
break;
|
||||
case '-':
|
||||
$operand1[$row][$column] -= $operand2[$row][$column];
|
||||
|
||||
break;
|
||||
case '*':
|
||||
$operand1[$row][$column] *= $operand2[$row][$column];
|
||||
|
||||
break;
|
||||
case '/':
|
||||
if ($operand2[$row][$column] == 0) {
|
||||
$operand1[$row][$column] = Information\ExcelError::DIV0();
|
||||
} else {
|
||||
$operand1[$row][$column] /= $operand2[$row][$column];
|
||||
}
|
||||
|
||||
break;
|
||||
case '^':
|
||||
$operand1[$row][$column] = $operand1[$row][$column] ** $operand2[$row][$column];
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new Exception('Unsupported numeric binary operation');
|
||||
}
|
||||
}
|
||||
}
|
||||
$result = $operand1;
|
||||
} else {
|
||||
// If we're dealing with non-matrix operations, execute the necessary operation
|
||||
switch ($operation) {
|
||||
// Addition
|
||||
case '+':
|
||||
$result = $operand1 + $operand2;
|
||||
|
||||
break;
|
||||
// Subtraction
|
||||
case '-':
|
||||
$result = $operand1 - $operand2;
|
||||
|
||||
break;
|
||||
// Multiplication
|
||||
case '*':
|
||||
$result = $operand1 * $operand2;
|
||||
|
||||
break;
|
||||
// Division
|
||||
case '/':
|
||||
if ($operand2 == 0) {
|
||||
// Trap for Divide by Zero error
|
||||
$stack->push('Error', Information\ExcelError::DIV0());
|
||||
$this->debugLog->writeDebugLog('Evaluation Result is %s', $this->showTypeDetails(Information\ExcelError::DIV0()));
|
||||
|
||||
return false;
|
||||
}
|
||||
$result = $operand1 / $operand2;
|
||||
|
||||
break;
|
||||
// Power
|
||||
case '^':
|
||||
$result = $operand1 ** $operand2;
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new Exception('Unsupported numeric binary operation');
|
||||
}
|
||||
}
|
||||
|
||||
// Log the result details
|
||||
@@ -5623,25 +5679,6 @@ class Calculation
|
||||
return $args;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $tokens
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function getTokensAsString($tokens)
|
||||
{
|
||||
$tokensStr = array_map(function ($token) {
|
||||
$value = $token['value'] ?? 'no value';
|
||||
while (is_array($value)) {
|
||||
$value = array_pop($value);
|
||||
}
|
||||
|
||||
return $value;
|
||||
}, $tokens);
|
||||
|
||||
return '[ ' . implode(' | ', $tokensStr) . ' ]';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed|string
|
||||
*/
|
||||
@@ -5710,4 +5747,20 @@ class Calculation
|
||||
{
|
||||
return (bool) $arg;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $operand1
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
private static function boolToString($operand1)
|
||||
{
|
||||
if (is_bool($operand1)) {
|
||||
$operand1 = ($operand1) ? self::$localeBoolean['TRUE'] : self::$localeBoolean['FALSE'];
|
||||
} elseif ($operand1 === null) {
|
||||
$operand1 = '';
|
||||
}
|
||||
|
||||
return $operand1;
|
||||
}
|
||||
}
|
||||
|
@@ -24,7 +24,7 @@ class DateValue
|
||||
* Excel Function:
|
||||
* DATEVALUE(dateValue)
|
||||
*
|
||||
* @param array|string $dateValue Text that represents a date in a Microsoft Excel date format.
|
||||
* @param null|array|string $dateValue Text that represents a date in a Microsoft Excel date format.
|
||||
* For example, "1/30/2008" or "30-Jan-2008" are text strings within
|
||||
* quotation marks that represent dates. Using the default date
|
||||
* system in Excel for Windows, date_text must represent a date from
|
||||
|
@@ -25,7 +25,7 @@ class TimeValue
|
||||
* Excel Function:
|
||||
* TIMEVALUE(timeValue)
|
||||
*
|
||||
* @param array|string $timeValue A text string that represents a time in any one of the Microsoft
|
||||
* @param null|array|string $timeValue A text string that represents a time in any one of the Microsoft
|
||||
* Excel time formats; for example, "6:45 PM" and "18:45" text strings
|
||||
* within quotation marks that represent time.
|
||||
* Date information in time_text is ignored.
|
||||
|
@@ -2,7 +2,11 @@
|
||||
|
||||
namespace PhpOffice\PhpSpreadsheet\Calculation\Engine\Operands;
|
||||
|
||||
use PhpOffice\PhpSpreadsheet\Calculation\Calculation;
|
||||
use PhpOffice\PhpSpreadsheet\Calculation\Exception;
|
||||
use PhpOffice\PhpSpreadsheet\Cell\Cell;
|
||||
use PhpOffice\PhpSpreadsheet\Cell\Coordinate;
|
||||
use PhpOffice\PhpSpreadsheet\Worksheet\Table;
|
||||
|
||||
final class StructuredReference implements Operand
|
||||
{
|
||||
@@ -11,8 +15,39 @@ final class StructuredReference implements Operand
|
||||
private const OPEN_BRACE = '[';
|
||||
private const CLOSE_BRACE = ']';
|
||||
|
||||
private const ITEM_SPECIFIER_ALL = '#All';
|
||||
private const ITEM_SPECIFIER_HEADERS = '#Headers';
|
||||
private const ITEM_SPECIFIER_DATA = '#Data';
|
||||
private const ITEM_SPECIFIER_TOTALS = '#Totals';
|
||||
private const ITEM_SPECIFIER_THIS_ROW = '#This Row';
|
||||
|
||||
private const ITEM_SPECIFIER_ROWS_SET = [
|
||||
self::ITEM_SPECIFIER_ALL,
|
||||
self::ITEM_SPECIFIER_HEADERS,
|
||||
self::ITEM_SPECIFIER_DATA,
|
||||
self::ITEM_SPECIFIER_TOTALS,
|
||||
];
|
||||
|
||||
private const TABLE_REFERENCE = '/([\p{L}_\\\\][\p{L}\p{N}\._]+)?(\[(?:[^\]\[]+|(?R))*+\])/miu';
|
||||
|
||||
private string $value;
|
||||
|
||||
private string $tableName;
|
||||
|
||||
private Table $table;
|
||||
|
||||
private string $reference;
|
||||
|
||||
private ?int $headersRow;
|
||||
|
||||
private int $firstDataRow;
|
||||
|
||||
private int $lastDataRow;
|
||||
|
||||
private ?int $totalsRow;
|
||||
|
||||
private array $columns;
|
||||
|
||||
public function __construct(string $structuredReference)
|
||||
{
|
||||
$this->value = $structuredReference;
|
||||
@@ -42,8 +77,268 @@ final class StructuredReference implements Operand
|
||||
return new self($val);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
* @throws \PhpOffice\PhpSpreadsheet\Exception
|
||||
*/
|
||||
public function parse(Cell $cell): string
|
||||
{
|
||||
$this->getTableStructure($cell);
|
||||
$cellRange = ($this->isRowReference()) ? $this->getRowReference($cell) : $this->getColumnReference();
|
||||
|
||||
return $cellRange;
|
||||
}
|
||||
|
||||
private function isRowReference(): bool
|
||||
{
|
||||
return strpos($this->value, '[@') !== false
|
||||
|| strpos($this->value, '[' . self::ITEM_SPECIFIER_THIS_ROW . ']') !== false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
* @throws \PhpOffice\PhpSpreadsheet\Exception
|
||||
*/
|
||||
private function getTableStructure(Cell $cell): void
|
||||
{
|
||||
preg_match(self::TABLE_REFERENCE, $this->value, $matches);
|
||||
|
||||
$this->tableName = $matches[1];
|
||||
$this->table = ($this->tableName === '')
|
||||
? $this->getTableForCell($cell)
|
||||
: $this->getTableByName($cell);
|
||||
$this->reference = $matches[2];
|
||||
$tableRange = Coordinate::getRangeBoundaries($this->table->getRange());
|
||||
|
||||
$this->headersRow = ($this->table->getShowHeaderRow()) ? (int) $tableRange[0][1] : null;
|
||||
$this->firstDataRow = ($this->table->getShowHeaderRow()) ? (int) $tableRange[0][1] + 1 : $tableRange[0][1];
|
||||
$this->totalsRow = ($this->table->getShowTotalsRow()) ? (int) $tableRange[1][1] : null;
|
||||
$this->lastDataRow = ($this->table->getShowTotalsRow()) ? (int) $tableRange[1][1] - 1 : $tableRange[1][1];
|
||||
|
||||
$this->columns = $this->getColumns($cell, $tableRange);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
* @throws \PhpOffice\PhpSpreadsheet\Exception
|
||||
*/
|
||||
private function getTableForCell(Cell $cell): Table
|
||||
{
|
||||
$tables = $cell->getWorksheet()->getTableCollection();
|
||||
foreach ($tables as $table) {
|
||||
/** @var Table $table */
|
||||
$range = $table->getRange();
|
||||
if ($cell->isInRange($range) === true) {
|
||||
$this->tableName = $table->getName();
|
||||
|
||||
return $table;
|
||||
}
|
||||
}
|
||||
|
||||
throw new Exception('Table for Structured Reference cannot be identified');
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
* @throws \PhpOffice\PhpSpreadsheet\Exception
|
||||
*/
|
||||
private function getTableByName(Cell $cell): Table
|
||||
{
|
||||
$table = $cell->getWorksheet()->getTableByName($this->tableName);
|
||||
|
||||
if ($table === null) {
|
||||
throw new Exception("Table {$this->tableName} for Structured Reference cannot be located");
|
||||
}
|
||||
|
||||
return $table;
|
||||
}
|
||||
|
||||
private function getColumns(Cell $cell, array $tableRange): array
|
||||
{
|
||||
$worksheet = $cell->getWorksheet();
|
||||
$cellReference = $cell->getCoordinate();
|
||||
|
||||
$columns = [];
|
||||
$lastColumn = ++$tableRange[1][0];
|
||||
for ($column = $tableRange[0][0]; $column !== $lastColumn; ++$column) {
|
||||
$columns[$column] = $worksheet
|
||||
->getCell($column . ($this->headersRow ?? ($this->firstDataRow - 1)))
|
||||
->getCalculatedValue();
|
||||
}
|
||||
|
||||
$cell = $worksheet->getCell($cellReference);
|
||||
|
||||
return $columns;
|
||||
}
|
||||
|
||||
private function getRowReference(Cell $cell): string
|
||||
{
|
||||
$reference = str_replace("\u{a0}", ' ', $this->reference);
|
||||
/** @var string $reference */
|
||||
$reference = str_replace('[' . self::ITEM_SPECIFIER_THIS_ROW . '],', '', $reference);
|
||||
|
||||
foreach ($this->columns as $columnId => $columnName) {
|
||||
$columnName = str_replace("\u{a0}", ' ', $columnName);
|
||||
$reference = $this->adjustRowReference($columnName, $reference, $cell, $columnId);
|
||||
}
|
||||
|
||||
/** @var string $reference */
|
||||
return $this->validateParsedReference(trim($reference, '[]@, '));
|
||||
}
|
||||
|
||||
private function adjustRowReference(string $columnName, string $reference, Cell $cell, string $columnId): string
|
||||
{
|
||||
if ($columnName !== '') {
|
||||
$cellReference = $columnId . $cell->getRow();
|
||||
$pattern1 = '/\[' . preg_quote($columnName) . '\]/miu';
|
||||
$pattern2 = '/@' . preg_quote($columnName) . '/miu';
|
||||
if (preg_match($pattern1, $reference) === 1) {
|
||||
$reference = preg_replace($pattern1, $cellReference, $reference);
|
||||
} elseif (preg_match($pattern2, $reference) === 1) {
|
||||
$reference = preg_replace($pattern2, $cellReference, $reference);
|
||||
}
|
||||
/** @var string $reference */
|
||||
}
|
||||
|
||||
return $reference;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
* @throws \PhpOffice\PhpSpreadsheet\Exception
|
||||
*/
|
||||
private function getColumnReference(): string
|
||||
{
|
||||
$reference = str_replace("\u{a0}", ' ', $this->reference);
|
||||
$startRow = ($this->totalsRow === null) ? $this->lastDataRow : $this->totalsRow;
|
||||
$endRow = ($this->headersRow === null) ? $this->firstDataRow : $this->headersRow;
|
||||
|
||||
[$startRow, $endRow] = $this->getRowsForColumnReference($reference, $startRow, $endRow);
|
||||
$reference = $this->getColumnsForColumnReference($reference, $startRow, $endRow);
|
||||
|
||||
$reference = trim($reference, '[]@, ');
|
||||
if (substr_count($reference, ':') > 1) {
|
||||
$cells = explode(':', $reference);
|
||||
$firstCell = array_shift($cells);
|
||||
$lastCell = array_pop($cells);
|
||||
$reference = "{$firstCell}:{$lastCell}";
|
||||
}
|
||||
|
||||
return $this->validateParsedReference($reference);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
* @throws \PhpOffice\PhpSpreadsheet\Exception
|
||||
*/
|
||||
private function validateParsedReference(string $reference): string
|
||||
{
|
||||
if (preg_match('/^' . Calculation::CALCULATION_REGEXP_CELLREF . ':' . Calculation::CALCULATION_REGEXP_CELLREF . '$/miu', $reference) !== 1) {
|
||||
if (preg_match('/^' . Calculation::CALCULATION_REGEXP_CELLREF . '$/miu', $reference) !== 1) {
|
||||
throw new Exception(
|
||||
"Invalid Structured Reference {$this->reference} {$reference}",
|
||||
Exception::CALCULATION_ENGINE_PUSH_TO_STACK
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return $reference;
|
||||
}
|
||||
|
||||
private function fullData(int $startRow, int $endRow): string
|
||||
{
|
||||
$columns = array_keys($this->columns);
|
||||
$firstColumn = array_shift($columns);
|
||||
$lastColumn = (empty($columns)) ? $firstColumn : array_pop($columns);
|
||||
|
||||
return "{$firstColumn}{$startRow}:{$lastColumn}{$endRow}";
|
||||
}
|
||||
|
||||
private function getMinimumRow(string $reference): int
|
||||
{
|
||||
switch ($reference) {
|
||||
case self::ITEM_SPECIFIER_ALL:
|
||||
case self::ITEM_SPECIFIER_HEADERS:
|
||||
return $this->headersRow ?? $this->firstDataRow;
|
||||
case self::ITEM_SPECIFIER_DATA:
|
||||
return $this->firstDataRow;
|
||||
case self::ITEM_SPECIFIER_TOTALS:
|
||||
return $this->totalsRow ?? $this->lastDataRow;
|
||||
}
|
||||
|
||||
return $this->headersRow ?? $this->firstDataRow;
|
||||
}
|
||||
|
||||
private function getMaximumRow(string $reference): int
|
||||
{
|
||||
switch ($reference) {
|
||||
case self::ITEM_SPECIFIER_HEADERS:
|
||||
return $this->headersRow ?? $this->firstDataRow;
|
||||
case self::ITEM_SPECIFIER_DATA:
|
||||
return $this->lastDataRow;
|
||||
case self::ITEM_SPECIFIER_ALL:
|
||||
case self::ITEM_SPECIFIER_TOTALS:
|
||||
return $this->totalsRow ?? $this->lastDataRow;
|
||||
}
|
||||
|
||||
return $this->totalsRow ?? $this->lastDataRow;
|
||||
}
|
||||
|
||||
public function value(): string
|
||||
{
|
||||
return $this->value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<int, int>
|
||||
*/
|
||||
private function getRowsForColumnReference(string &$reference, int $startRow, int $endRow): array
|
||||
{
|
||||
$rowsSelected = false;
|
||||
foreach (self::ITEM_SPECIFIER_ROWS_SET as $rowReference) {
|
||||
$pattern = '/\[' . $rowReference . '\]/mui';
|
||||
/** @var string $reference */
|
||||
if (preg_match($pattern, $reference) === 1) {
|
||||
if (($rowReference === self::ITEM_SPECIFIER_HEADERS) && ($this->table->getShowHeaderRow() === false)) {
|
||||
throw new Exception(
|
||||
'Table Headers are Hidden, and should not be Referenced',
|
||||
Exception::CALCULATION_ENGINE_PUSH_TO_STACK
|
||||
);
|
||||
}
|
||||
$rowsSelected = true;
|
||||
$startRow = min($startRow, $this->getMinimumRow($rowReference));
|
||||
$endRow = max($endRow, $this->getMaximumRow($rowReference));
|
||||
$reference = preg_replace($pattern, '', $reference);
|
||||
}
|
||||
}
|
||||
if ($rowsSelected === false) {
|
||||
// If there isn't any Special Item Identifier specified, then the selection defaults to data rows only.
|
||||
$startRow = $this->firstDataRow;
|
||||
$endRow = $this->lastDataRow;
|
||||
}
|
||||
|
||||
return [$startRow, $endRow];
|
||||
}
|
||||
|
||||
private function getColumnsForColumnReference(string $reference, int $startRow, int $endRow): string
|
||||
{
|
||||
$columnsSelected = false;
|
||||
foreach ($this->columns as $columnId => $columnName) {
|
||||
$columnName = str_replace("\u{a0}", ' ', $columnName);
|
||||
$cellFrom = "{$columnId}{$startRow}";
|
||||
$cellTo = "{$columnId}{$endRow}";
|
||||
$cellReference = ($cellFrom === $cellTo) ? $cellFrom : "{$cellFrom}:{$cellTo}";
|
||||
$pattern = '/\[' . preg_quote($columnName) . '\]/mui';
|
||||
if (preg_match($pattern, $reference) === 1) {
|
||||
$columnsSelected = true;
|
||||
$reference = preg_replace($pattern, $cellReference, $reference);
|
||||
}
|
||||
/** @var string $reference */
|
||||
}
|
||||
if ($columnsSelected === false) {
|
||||
return $this->fullData($startRow, $endRow);
|
||||
}
|
||||
|
||||
return $reference;
|
||||
}
|
||||
}
|
||||
|
@@ -133,7 +133,7 @@ class BesselJ
|
||||
return self::besselj2b($ax, $ord, $x);
|
||||
}
|
||||
|
||||
private static function besselj2a(float $ax, int $ord, float $x)
|
||||
private static function besselj2a(float $ax, int $ord, float $x): float
|
||||
{
|
||||
$tox = 2.0 / $ax;
|
||||
$bjm = self::besselJ0($ax);
|
||||
@@ -148,7 +148,7 @@ class BesselJ
|
||||
return ($x < 0.0 && ($ord % 2) == 1) ? -$ans : $ans;
|
||||
}
|
||||
|
||||
private static function besselj2b(float $ax, int $ord, float $x)
|
||||
private static function besselj2b(float $ax, int $ord, float $x): float
|
||||
{
|
||||
$tox = 2.0 / $ax;
|
||||
$jsum = false;
|
||||
|
@@ -11,6 +11,7 @@ abstract class ConvertBase
|
||||
{
|
||||
use ArrayEnabled;
|
||||
|
||||
/** @param mixed $value */
|
||||
protected static function validateValue($value): string
|
||||
{
|
||||
if (is_bool($value)) {
|
||||
@@ -29,6 +30,7 @@ abstract class ConvertBase
|
||||
return strtoupper((string) $value);
|
||||
}
|
||||
|
||||
/** @param mixed $places */
|
||||
protected static function validatePlaces($places = null): ?int
|
||||
{
|
||||
if ($places === null) {
|
||||
|
@@ -572,7 +572,7 @@ class ConvertUOM
|
||||
return ($baseValue * self::$unitConversions[$fromCategory][$toUOM]) / $toMultiplier;
|
||||
}
|
||||
|
||||
private static function getUOMDetails(string $uom)
|
||||
private static function getUOMDetails(string $uom): array
|
||||
{
|
||||
if (isset(self::$conversionUnits[$uom])) {
|
||||
$unitCategory = self::$conversionUnits[$uom]['Group'];
|
||||
@@ -678,7 +678,7 @@ class ConvertUOM
|
||||
return $value;
|
||||
}
|
||||
|
||||
private static function resolveTemperatureSynonyms(string $uom)
|
||||
private static function resolveTemperatureSynonyms(string $uom): string
|
||||
{
|
||||
switch ($uom) {
|
||||
case 'fah':
|
||||
|
@@ -10,7 +10,7 @@ class Erf
|
||||
{
|
||||
use ArrayEnabled;
|
||||
|
||||
private static $twoSqrtPi = 1.128379167095512574;
|
||||
private const TWO_SQRT_PI = 1.128379167095512574;
|
||||
|
||||
/**
|
||||
* ERF.
|
||||
@@ -77,11 +77,16 @@ class Erf
|
||||
return self::ERF($limit);
|
||||
}
|
||||
|
||||
//
|
||||
// Private method to calculate the erf value
|
||||
//
|
||||
/**
|
||||
* Method to calculate the erf value.
|
||||
*
|
||||
* @param float|int|string $value
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public static function erfValue($value)
|
||||
{
|
||||
$value = (float) $value;
|
||||
if (abs($value) > 2.2) {
|
||||
return 1 - ErfC::ERFC($value);
|
||||
}
|
||||
@@ -100,6 +105,6 @@ class Erf
|
||||
}
|
||||
} while (abs($term / $sum) > Functions::PRECISION);
|
||||
|
||||
return self::$twoSqrtPi * $sum;
|
||||
return self::TWO_SQRT_PI * $sum;
|
||||
}
|
||||
}
|
||||
|
@@ -43,13 +43,18 @@ class ErfC
|
||||
return ExcelError::VALUE();
|
||||
}
|
||||
|
||||
//
|
||||
// Private method to calculate the erfc value
|
||||
//
|
||||
private static $oneSqrtPi = 0.564189583547756287;
|
||||
private const ONE_SQRT_PI = 0.564189583547756287;
|
||||
|
||||
/**
|
||||
* Method to calculate the erfc value.
|
||||
*
|
||||
* @param float|int|string $value
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
private static function erfcValue($value)
|
||||
{
|
||||
$value = (float) $value;
|
||||
if (abs($value) < 2.2) {
|
||||
return 1 - Erf::erfValue($value);
|
||||
}
|
||||
@@ -72,6 +77,6 @@ class ErfC
|
||||
$q2 = $b / $d;
|
||||
} while ((abs($q1 - $q2) / $q2) > Functions::PRECISION);
|
||||
|
||||
return self::$oneSqrtPi * exp(-$value * $value) * $q2;
|
||||
return self::ONE_SQRT_PI * exp(-$value * $value) * $q2;
|
||||
}
|
||||
}
|
||||
|
@@ -6,6 +6,8 @@ use PhpOffice\PhpSpreadsheet\Exception as PhpSpreadsheetException;
|
||||
|
||||
class Exception extends PhpSpreadsheetException
|
||||
{
|
||||
public const CALCULATION_ENGINE_PUSH_TO_STACK = 1;
|
||||
|
||||
/**
|
||||
* Error handler callback.
|
||||
*
|
||||
|
@@ -12,8 +12,6 @@ use PhpOffice\PhpSpreadsheet\Calculation\Financial\TreasuryBill;
|
||||
|
||||
/**
|
||||
* @deprecated 1.18.0
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
class Financial
|
||||
{
|
||||
@@ -543,7 +541,7 @@ class Financial
|
||||
* date when the security is traded to the buyer.
|
||||
* @param mixed $maturity The security's maturity date.
|
||||
* The maturity date is the date when the security expires.
|
||||
* @param int $price The security's price per $100 face value
|
||||
* @param mixed $price The security's price per $100 face value
|
||||
* @param int $redemption The security's redemption value per $100 face value
|
||||
* @param int $basis The type of day count to use.
|
||||
* 0 or omitted US (NASD) 30/360
|
||||
@@ -1004,7 +1002,7 @@ class Financial
|
||||
* is traded to the buyer.
|
||||
* @param mixed $maturity The security's maturity date.
|
||||
* The maturity date is the date when the security expires.
|
||||
* @param int $discount The security's discount rate
|
||||
* @param mixed $discount The security's discount rate
|
||||
* @param int $redemption The security's redemption value per $100 face value
|
||||
* @param int $basis The type of day count to use.
|
||||
* 0 or omitted US (NASD) 30/360
|
||||
@@ -1035,8 +1033,8 @@ class Financial
|
||||
* @param mixed $maturity The security's maturity date.
|
||||
* The maturity date is the date when the security expires.
|
||||
* @param mixed $issue The security's issue date
|
||||
* @param int $rate The security's interest rate at date of issue
|
||||
* @param int $yield The security's annual yield
|
||||
* @param mixed $rate The security's interest rate at date of issue
|
||||
* @param mixed $yield The security's annual yield
|
||||
* @param int $basis The type of day count to use.
|
||||
* 0 or omitted US (NASD) 30/360
|
||||
* 1 Actual/actual
|
||||
@@ -1216,7 +1214,7 @@ class Financial
|
||||
* Treasury bill is traded to the buyer.
|
||||
* @param mixed $maturity The Treasury bill's maturity date.
|
||||
* The maturity date is the date when the Treasury bill expires.
|
||||
* @param int $discount The Treasury bill's discount rate
|
||||
* @param mixed $discount The Treasury bill's discount rate
|
||||
*
|
||||
* @return float|string Result, or a string containing an error
|
||||
*/
|
||||
@@ -1239,7 +1237,7 @@ class Financial
|
||||
* when the Treasury bill is traded to the buyer.
|
||||
* @param mixed $maturity The Treasury bill's maturity date.
|
||||
* The maturity date is the date when the Treasury bill expires.
|
||||
* @param int $discount The Treasury bill's discount rate
|
||||
* @param mixed $discount The Treasury bill's discount rate
|
||||
*
|
||||
* @return float|string Result, or a string containing an error
|
||||
*/
|
||||
@@ -1262,7 +1260,7 @@ class Financial
|
||||
* when the Treasury bill is traded to the buyer.
|
||||
* @param mixed $maturity The Treasury bill's maturity date.
|
||||
* The maturity date is the date when the Treasury bill expires.
|
||||
* @param int $price The Treasury bill's price per $100 face value
|
||||
* @param mixed $price The Treasury bill's price per $100 face value
|
||||
*
|
||||
* @return float|mixed|string
|
||||
*/
|
||||
@@ -1342,7 +1340,7 @@ class Financial
|
||||
* is traded to the buyer.
|
||||
* @param mixed $maturity The security's maturity date.
|
||||
* The maturity date is the date when the security expires.
|
||||
* @param int $price The security's price per $100 face value
|
||||
* @param mixed $price The security's price per $100 face value
|
||||
* @param int $redemption The security's redemption value per $100 face value
|
||||
* @param int $basis The type of day count to use.
|
||||
* 0 or omitted US (NASD) 30/360
|
||||
@@ -1373,8 +1371,8 @@ class Financial
|
||||
* @param mixed $maturity The security's maturity date.
|
||||
* The maturity date is the date when the security expires.
|
||||
* @param mixed $issue The security's issue date
|
||||
* @param int $rate The security's interest rate at date of issue
|
||||
* @param int $price The security's price per $100 face value
|
||||
* @param mixed $rate The security's interest rate at date of issue
|
||||
* @param mixed $price The security's price per $100 face value
|
||||
* @param int $basis The type of day count to use.
|
||||
* 0 or omitted US (NASD) 30/360
|
||||
* 1 Actual/actual
|
||||
|
@@ -171,8 +171,9 @@ class Amortization
|
||||
$yearFrac = $yearFracx;
|
||||
|
||||
if (
|
||||
($basis == FinancialConstants::BASIS_DAYS_PER_YEAR_ACTUAL) &&
|
||||
($yearFrac < 1) && (Functions::scalar(DateTimeExcel\Helpers::isLeapYear($purchasedYear)))
|
||||
$basis == FinancialConstants::BASIS_DAYS_PER_YEAR_ACTUAL
|
||||
&& $yearFrac < 1
|
||||
&& DateTimeExcel\Helpers::isLeapYear(Functions::scalar($purchasedYear))
|
||||
) {
|
||||
$yearFrac *= 365 / 366;
|
||||
}
|
||||
|
@@ -199,7 +199,8 @@ class Interest
|
||||
return $close ? $rate : ExcelError::NAN();
|
||||
}
|
||||
|
||||
private static function rateNextGuess($rate, $numberOfPeriods, $payment, $presentValue, $futureValue, $type)
|
||||
/** @return float|string */
|
||||
private static function rateNextGuess(float $rate, int $numberOfPeriods, float $payment, float $presentValue, float $futureValue, int $type)
|
||||
{
|
||||
if ($rate == 0.0) {
|
||||
return ExcelError::NAN();
|
||||
|
@@ -6,8 +6,10 @@ use PhpOffice\PhpSpreadsheet\Calculation\Financial\Constants as FinancialConstan
|
||||
|
||||
class InterestAndPrincipal
|
||||
{
|
||||
/** @var float */
|
||||
protected $interest;
|
||||
|
||||
/** @var float */
|
||||
protected $principal;
|
||||
|
||||
public function __construct(
|
||||
@@ -24,7 +26,7 @@ class InterestAndPrincipal
|
||||
$principal = 0.0;
|
||||
for ($i = 1; $i <= $period; ++$i) {
|
||||
$interest = ($type === FinancialConstants::PAYMENT_BEGINNING_OF_PERIOD && $i == 1) ? 0 : -$capital * $rate;
|
||||
$principal = $payment - $interest;
|
||||
$principal = (float) $payment - $interest;
|
||||
$capital += $principal;
|
||||
}
|
||||
|
||||
|
@@ -51,8 +51,11 @@ class NonPeriodic
|
||||
$f2 = self::xnpvOrdered($x2, $values, $dates, false);
|
||||
$found = false;
|
||||
for ($i = 0; $i < self::FINANCIAL_MAX_ITERATIONS; ++$i) {
|
||||
if (!is_numeric($f1) || !is_numeric($f2)) {
|
||||
break;
|
||||
if (!is_numeric($f1)) {
|
||||
return $f1;
|
||||
}
|
||||
if (!is_numeric($f2)) {
|
||||
return $f2;
|
||||
}
|
||||
$f1 = (float) $f1;
|
||||
$f2 = (float) $f2;
|
||||
@@ -68,11 +71,32 @@ class NonPeriodic
|
||||
$f2 = self::xnpvOrdered($x2, $values, $dates, false);
|
||||
}
|
||||
}
|
||||
if (!$found) {
|
||||
return ExcelError::NAN();
|
||||
if ($found) {
|
||||
return self::xirrPart3($values, $dates, $x1, $x2);
|
||||
}
|
||||
|
||||
return self::xirrPart3($values, $dates, $x1, $x2);
|
||||
// Newton-Raphson didn't work - try bisection
|
||||
$x1 = $guess - 0.5;
|
||||
$x2 = $guess + 0.5;
|
||||
for ($i = 0; $i < self::FINANCIAL_MAX_ITERATIONS; ++$i) {
|
||||
$f1 = self::xnpvOrdered($x1, $values, $dates, false, true);
|
||||
$f2 = self::xnpvOrdered($x2, $values, $dates, false, true);
|
||||
if (!is_numeric($f1) || !is_numeric($f2)) {
|
||||
break;
|
||||
}
|
||||
if ($f1 * $f2 <= 0) {
|
||||
$found = true;
|
||||
|
||||
break;
|
||||
}
|
||||
$x1 -= 0.5;
|
||||
$x2 += 0.5;
|
||||
}
|
||||
if ($found) {
|
||||
return self::xirrBisection($values, $dates, $x1, $x2);
|
||||
}
|
||||
|
||||
return ExcelError::NAN();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -190,6 +214,45 @@ class NonPeriodic
|
||||
return $rslt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return float|string
|
||||
*/
|
||||
private static function xirrBisection(array $values, array $dates, float $x1, float $x2)
|
||||
{
|
||||
$rslt = ExcelError::NAN();
|
||||
for ($i = 0; $i < self::FINANCIAL_MAX_ITERATIONS; ++$i) {
|
||||
$rslt = ExcelError::NAN();
|
||||
$f1 = self::xnpvOrdered($x1, $values, $dates, false, true);
|
||||
$f2 = self::xnpvOrdered($x2, $values, $dates, false, true);
|
||||
if (!is_numeric($f1) || !is_numeric($f2)) {
|
||||
break;
|
||||
}
|
||||
$f1 = (float) $f1;
|
||||
$f2 = (float) $f2;
|
||||
if (abs($f1) < self::FINANCIAL_PRECISION && abs($f2) < self::FINANCIAL_PRECISION) {
|
||||
break;
|
||||
}
|
||||
if ($f1 * $f2 > 0) {
|
||||
break;
|
||||
}
|
||||
$rslt = ($x1 + $x2) / 2;
|
||||
$f3 = self::xnpvOrdered($rslt, $values, $dates, false, true);
|
||||
if (!is_float($f3)) {
|
||||
break;
|
||||
}
|
||||
if ($f3 * $f1 < 0) {
|
||||
$x2 = $rslt;
|
||||
} else {
|
||||
$x1 = $rslt;
|
||||
}
|
||||
if (abs($f3) < self::FINANCIAL_PRECISION) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $rslt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $rate
|
||||
* @param mixed $values
|
||||
@@ -197,7 +260,7 @@ class NonPeriodic
|
||||
*
|
||||
* @return float|string
|
||||
*/
|
||||
private static function xnpvOrdered($rate, $values, $dates, bool $ordered = true)
|
||||
private static function xnpvOrdered($rate, $values, $dates, bool $ordered = true, bool $capAtNegative1 = false)
|
||||
{
|
||||
$rate = Functions::flattenSingleValue($rate);
|
||||
$values = Functions::flattenArray($values);
|
||||
@@ -206,6 +269,9 @@ class NonPeriodic
|
||||
|
||||
try {
|
||||
self::validateXnpv($rate, $values, $dates);
|
||||
if ($capAtNegative1 && $rate <= -1) {
|
||||
$rate = -1.0 + 1.0E-10;
|
||||
}
|
||||
$date0 = DateTimeExcel\Helpers::getDateValue($dates[0]);
|
||||
} catch (Exception $e) {
|
||||
return $e->getMessage();
|
||||
@@ -225,7 +291,7 @@ class NonPeriodic
|
||||
if ($date0 > $datei) {
|
||||
$dif = $ordered ? ExcelError::NAN() : -((int) DateTimeExcel\Difference::interval($datei, $date0, 'd'));
|
||||
} else {
|
||||
$dif = DateTimeExcel\Difference::interval($date0, $datei, 'd');
|
||||
$dif = Functions::scalar(DateTimeExcel\Difference::interval($date0, $datei, 'd'));
|
||||
}
|
||||
if (!is_numeric($dif)) {
|
||||
return $dif;
|
||||
|
@@ -144,6 +144,7 @@ class Periodic
|
||||
* Returns the Net Present Value of a cash flow series given a discount rate.
|
||||
*
|
||||
* @param mixed $rate
|
||||
* @param array $args
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
|
@@ -200,7 +200,7 @@ class Coupons
|
||||
}
|
||||
|
||||
/** @var int */
|
||||
$daysPerYear = Helpers::daysPerYear(DateTimeExcel\DateParts::year($settlement), $basis);
|
||||
$daysPerYear = Helpers::daysPerYear(Functions::Scalar(DateTimeExcel\DateParts::year($settlement)), $basis);
|
||||
$next = self::couponFirstPeriodDate($settlement, $maturity, $frequency, self::PERIOD_DATE_NEXT);
|
||||
|
||||
if ($basis === FinancialConstants::BASIS_DAYS_PER_YEAR_NASD) {
|
||||
|
@@ -208,6 +208,7 @@ class Depreciation
|
||||
return $syd;
|
||||
}
|
||||
|
||||
/** @param mixed $cost */
|
||||
private static function validateCost($cost, bool $negativeValueAllowed = false): float
|
||||
{
|
||||
$cost = FinancialValidations::validateFloat($cost);
|
||||
@@ -218,6 +219,7 @@ class Depreciation
|
||||
return $cost;
|
||||
}
|
||||
|
||||
/** @param mixed $salvage */
|
||||
private static function validateSalvage($salvage, bool $negativeValueAllowed = false): float
|
||||
{
|
||||
$salvage = FinancialValidations::validateFloat($salvage);
|
||||
@@ -228,6 +230,7 @@ class Depreciation
|
||||
return $salvage;
|
||||
}
|
||||
|
||||
/** @param mixed $life */
|
||||
private static function validateLife($life, bool $negativeValueAllowed = false): float
|
||||
{
|
||||
$life = FinancialValidations::validateFloat($life);
|
||||
@@ -238,6 +241,7 @@ class Depreciation
|
||||
return $life;
|
||||
}
|
||||
|
||||
/** @param mixed $period */
|
||||
private static function validatePeriod($period, bool $negativeValueAllowed = false): float
|
||||
{
|
||||
$period = FinancialValidations::validateFloat($period);
|
||||
@@ -248,6 +252,7 @@ class Depreciation
|
||||
return $period;
|
||||
}
|
||||
|
||||
/** @param mixed $month */
|
||||
private static function validateMonth($month): int
|
||||
{
|
||||
$month = FinancialValidations::validateInt($month);
|
||||
@@ -258,6 +263,7 @@ class Depreciation
|
||||
return $month;
|
||||
}
|
||||
|
||||
/** @param mixed $factor */
|
||||
private static function validateFactor($factor): float
|
||||
{
|
||||
$factor = FinancialValidations::validateFloat($factor);
|
||||
|
@@ -70,10 +70,10 @@ class Price
|
||||
return $e->getMessage();
|
||||
}
|
||||
|
||||
$dsc = Coupons::COUPDAYSNC($settlement, $maturity, $frequency, $basis);
|
||||
$e = Coupons::COUPDAYS($settlement, $maturity, $frequency, $basis);
|
||||
$n = Coupons::COUPNUM($settlement, $maturity, $frequency, $basis);
|
||||
$a = Coupons::COUPDAYBS($settlement, $maturity, $frequency, $basis);
|
||||
$dsc = (float) Coupons::COUPDAYSNC($settlement, $maturity, $frequency, $basis);
|
||||
$e = (float) Coupons::COUPDAYS($settlement, $maturity, $frequency, $basis);
|
||||
$n = (int) Coupons::COUPNUM($settlement, $maturity, $frequency, $basis);
|
||||
$a = (float) Coupons::COUPDAYBS($settlement, $maturity, $frequency, $basis);
|
||||
|
||||
$baseYF = 1.0 + ($yield / $frequency);
|
||||
$rfp = 100 * ($rate / $frequency);
|
||||
@@ -195,7 +195,7 @@ class Price
|
||||
return $e->getMessage();
|
||||
}
|
||||
|
||||
$daysPerYear = Functions::scalar(Helpers::daysPerYear(DateTimeExcel\DateParts::year($settlement), $basis));
|
||||
$daysPerYear = Helpers::daysPerYear(Functions::scalar(DateTimeExcel\DateParts::year($settlement)), $basis);
|
||||
if (!is_numeric($daysPerYear)) {
|
||||
return $daysPerYear;
|
||||
}
|
||||
@@ -276,7 +276,7 @@ class Price
|
||||
$daysBetweenSettlementAndMaturity = DateTimeExcel\YearFrac::fraction($settlement, $maturity, $basis);
|
||||
if (!is_numeric($daysBetweenSettlementAndMaturity)) {
|
||||
// return date error
|
||||
return $daysBetweenSettlementAndMaturity;
|
||||
return Functions::scalar($daysBetweenSettlementAndMaturity);
|
||||
}
|
||||
|
||||
return $investment / (1 - ($discount * $daysBetweenSettlementAndMaturity));
|
||||
|
@@ -57,7 +57,7 @@ class Yields
|
||||
return $e->getMessage();
|
||||
}
|
||||
|
||||
$daysPerYear = Helpers::daysPerYear(DateTimeExcel\DateParts::year($settlement), $basis);
|
||||
$daysPerYear = Helpers::daysPerYear(Functions::scalar(DateTimeExcel\DateParts::year($settlement)), $basis);
|
||||
if (!is_numeric($daysPerYear)) {
|
||||
return $daysPerYear;
|
||||
}
|
||||
@@ -122,7 +122,7 @@ class Yields
|
||||
return $e->getMessage();
|
||||
}
|
||||
|
||||
$daysPerYear = Helpers::daysPerYear(DateTimeExcel\DateParts::year($settlement), $basis);
|
||||
$daysPerYear = Helpers::daysPerYear(Functions::scalar(DateTimeExcel\DateParts::year($settlement)), $basis);
|
||||
if (!is_numeric($daysPerYear)) {
|
||||
return $daysPerYear;
|
||||
}
|
||||
|
@@ -130,22 +130,26 @@ class Functions
|
||||
return '#Not Yet Implemented';
|
||||
}
|
||||
|
||||
public static function isMatrixValue($idx)
|
||||
/** @param mixed $idx */
|
||||
public static function isMatrixValue($idx): bool
|
||||
{
|
||||
return (substr_count($idx, '.') <= 1) || (preg_match('/\.[A-Z]/', $idx) > 0);
|
||||
}
|
||||
|
||||
public static function isValue($idx)
|
||||
/** @param mixed $idx */
|
||||
public static function isValue($idx): bool
|
||||
{
|
||||
return substr_count($idx, '.') === 0;
|
||||
}
|
||||
|
||||
public static function isCellValue($idx)
|
||||
/** @param mixed $idx */
|
||||
public static function isCellValue($idx): bool
|
||||
{
|
||||
return substr_count($idx, '.') > 1;
|
||||
}
|
||||
|
||||
public static function ifCondition($condition)
|
||||
/** @param mixed $condition */
|
||||
public static function ifCondition($condition): string
|
||||
{
|
||||
$condition = self::flattenSingleValue($condition);
|
||||
|
||||
@@ -180,6 +184,11 @@ class Functions
|
||||
return str_replace('""""', '""', $operator . $operand);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $operand
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
private static function operandSpecialHandling($operand)
|
||||
{
|
||||
if (is_numeric($operand) || is_bool($operand)) {
|
||||
@@ -635,7 +644,7 @@ class Functions
|
||||
public static function expandDefinedName(string $coordinate, Cell $cell): string
|
||||
{
|
||||
$worksheet = $cell->getWorksheet();
|
||||
$spreadsheet = $worksheet->getParent();
|
||||
$spreadsheet = $worksheet->getParentOrThrow();
|
||||
// Uppercase coordinate
|
||||
$pCoordinatex = strtoupper($coordinate);
|
||||
// Eliminate leading equal sign
|
||||
|
@@ -49,7 +49,7 @@ class Value
|
||||
$cellValue = Functions::trimTrailingRange($value);
|
||||
if (preg_match('/^' . Calculation::CALCULATION_REGEXP_CELLREF . '$/ui', $cellValue) === 1) {
|
||||
[$worksheet, $cellValue] = Worksheet::extractSheetTitle($cellValue, true);
|
||||
if (!empty($worksheet) && $cell->getWorksheet()->getParent()->getSheetByName($worksheet) === null) {
|
||||
if (!empty($worksheet) && $cell->getWorksheet()->getParentOrThrow()->getSheetByName($worksheet) === null) {
|
||||
return false;
|
||||
}
|
||||
[$column, $row] = Coordinate::indexesFromString($cellValue);
|
||||
@@ -60,7 +60,7 @@ class Value
|
||||
return true;
|
||||
}
|
||||
|
||||
$namedRange = $cell->getWorksheet()->getParent()->getNamedRange($value);
|
||||
$namedRange = $cell->getWorksheet()->getParentOrThrow()->getNamedRange($value);
|
||||
|
||||
return $namedRange instanceof NamedRange;
|
||||
}
|
||||
@@ -227,7 +227,7 @@ class Value
|
||||
$worksheetName = str_replace("''", "'", trim($matches[2], "'"));
|
||||
|
||||
$worksheet = (!empty($worksheetName))
|
||||
? $cell->getWorksheet()->getParent()->getSheetByName($worksheetName)
|
||||
? $cell->getWorksheet()->getParentOrThrow()->getSheetByName($worksheetName)
|
||||
: $cell->getWorksheet();
|
||||
|
||||
return ($worksheet !== null) ? $worksheet->getCell($fullCellReference)->isFormula() : ExcelError::REF();
|
||||
|
@@ -4,6 +4,7 @@ namespace PhpOffice\PhpSpreadsheet\Calculation\Internal;
|
||||
|
||||
class MakeMatrix
|
||||
{
|
||||
/** @param array $args */
|
||||
public static function make(...$args): array
|
||||
{
|
||||
return $args;
|
||||
|
@@ -33,23 +33,9 @@ class Operations
|
||||
*/
|
||||
public static function logicalAnd(...$args)
|
||||
{
|
||||
$args = Functions::flattenArray($args);
|
||||
|
||||
if (count($args) == 0) {
|
||||
return ExcelError::VALUE();
|
||||
}
|
||||
|
||||
$args = array_filter($args, function ($value) {
|
||||
return $value !== null || (is_string($value) && trim($value) == '');
|
||||
return self::countTrueValues($args, function (int $trueValueCount, int $count): bool {
|
||||
return $trueValueCount === $count;
|
||||
});
|
||||
|
||||
$returnValue = self::countTrueValues($args);
|
||||
if (is_string($returnValue)) {
|
||||
return $returnValue;
|
||||
}
|
||||
$argCount = count($args);
|
||||
|
||||
return ($returnValue > 0) && ($returnValue == $argCount);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -74,22 +60,9 @@ class Operations
|
||||
*/
|
||||
public static function logicalOr(...$args)
|
||||
{
|
||||
$args = Functions::flattenArray($args);
|
||||
|
||||
if (count($args) == 0) {
|
||||
return ExcelError::VALUE();
|
||||
}
|
||||
|
||||
$args = array_filter($args, function ($value) {
|
||||
return $value !== null || (is_string($value) && trim($value) == '');
|
||||
return self::countTrueValues($args, function (int $trueValueCount): bool {
|
||||
return $trueValueCount > 0;
|
||||
});
|
||||
|
||||
$returnValue = self::countTrueValues($args);
|
||||
if (is_string($returnValue)) {
|
||||
return $returnValue;
|
||||
}
|
||||
|
||||
return $returnValue > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -116,22 +89,9 @@ class Operations
|
||||
*/
|
||||
public static function logicalXor(...$args)
|
||||
{
|
||||
$args = Functions::flattenArray($args);
|
||||
|
||||
if (count($args) == 0) {
|
||||
return ExcelError::VALUE();
|
||||
}
|
||||
|
||||
$args = array_filter($args, function ($value) {
|
||||
return $value !== null || (is_string($value) && trim($value) == '');
|
||||
return self::countTrueValues($args, function (int $trueValueCount): bool {
|
||||
return $trueValueCount % 2 === 1;
|
||||
});
|
||||
|
||||
$returnValue = self::countTrueValues($args);
|
||||
if (is_string($returnValue)) {
|
||||
return $returnValue;
|
||||
}
|
||||
|
||||
return $returnValue % 2 == 1;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -177,31 +137,36 @@ class Operations
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int|string
|
||||
* @return bool|string
|
||||
*/
|
||||
private static function countTrueValues(array $args)
|
||||
private static function countTrueValues(array $args, callable $func)
|
||||
{
|
||||
$trueValueCount = 0;
|
||||
$count = 0;
|
||||
|
||||
foreach ($args as $arg) {
|
||||
$aArgs = Functions::flattenArrayIndexed($args);
|
||||
foreach ($aArgs as $k => $arg) {
|
||||
++$count;
|
||||
// Is it a boolean value?
|
||||
if (is_bool($arg)) {
|
||||
$trueValueCount += $arg;
|
||||
} elseif ((is_numeric($arg)) && (!is_string($arg))) {
|
||||
$trueValueCount += ((int) $arg != 0);
|
||||
} elseif (is_string($arg)) {
|
||||
$isLiteral = !Functions::isCellValue($k);
|
||||
$arg = mb_strtoupper($arg, 'UTF-8');
|
||||
if (($arg == 'TRUE') || ($arg == Calculation::getTRUE())) {
|
||||
$arg = true;
|
||||
} elseif (($arg == 'FALSE') || ($arg == Calculation::getFALSE())) {
|
||||
$arg = false;
|
||||
if ($isLiteral && ($arg == 'TRUE' || $arg == Calculation::getTRUE())) {
|
||||
++$trueValueCount;
|
||||
} elseif ($isLiteral && ($arg == 'FALSE' || $arg == Calculation::getFALSE())) {
|
||||
//$trueValueCount += 0;
|
||||
} else {
|
||||
return ExcelError::VALUE();
|
||||
--$count;
|
||||
}
|
||||
$trueValueCount += ($arg != 0);
|
||||
} elseif (is_int($arg) || is_float($arg)) {
|
||||
$trueValueCount += (int) ($arg != 0);
|
||||
} else {
|
||||
--$count;
|
||||
}
|
||||
}
|
||||
|
||||
return $trueValueCount;
|
||||
return ($count === 0) ? ExcelError::VALUE() : $func($trueValueCount, $count);
|
||||
}
|
||||
}
|
||||
|
@@ -27,7 +27,7 @@ class Formula
|
||||
$cellReference = $matches[6] . $matches[7];
|
||||
$worksheetName = trim($matches[3], "'");
|
||||
$worksheet = (!empty($worksheetName))
|
||||
? $cell->getWorksheet()->getParent()->getSheetByName($worksheetName)
|
||||
? $cell->getWorksheet()->getParentOrThrow()->getSheetByName($worksheetName)
|
||||
: $cell->getWorksheet();
|
||||
|
||||
if (
|
||||
|
@@ -66,7 +66,7 @@ class Helpers
|
||||
}
|
||||
|
||||
$worksheet = ($sheetName !== '')
|
||||
? $cell->getWorksheet()->getParent()->getSheetByName($sheetName)
|
||||
? $cell->getWorksheet()->getParentOrThrow()->getSheetByName($sheetName)
|
||||
: $cell->getWorksheet();
|
||||
|
||||
return [$cellAddress, $worksheet, $sheetName];
|
||||
|
@@ -108,7 +108,7 @@ class Offset
|
||||
}
|
||||
|
||||
$worksheet = ($sheetName !== '')
|
||||
? $cell->getWorksheet()->getParent()->getSheetByName($sheetName)
|
||||
? $cell->getWorksheet()->getParentOrThrow()->getSheetByName($sheetName)
|
||||
: $cell->getWorksheet();
|
||||
|
||||
return [$cellAddress, $worksheet];
|
||||
|
@@ -766,7 +766,7 @@ class MathTrig
|
||||
* @param string $criteria the criteria that defines which cells will be summed
|
||||
* @param mixed $sumRange
|
||||
*
|
||||
* @return float|string
|
||||
* @return null|float|string
|
||||
*/
|
||||
public static function SUMIF($range, $criteria, $sumRange = [])
|
||||
{
|
||||
|
@@ -40,7 +40,7 @@ class Combinations
|
||||
return $e->getMessage();
|
||||
}
|
||||
|
||||
return round(Factorial::fact($numObjs) / Factorial::fact($numObjs - $numInSet)) / Factorial::fact($numInSet);
|
||||
return round(Factorial::fact($numObjs) / Factorial::fact($numObjs - $numInSet)) / Factorial::fact($numInSet); // @phpstan-ignore-line
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -85,7 +85,7 @@ class Combinations
|
||||
}
|
||||
|
||||
return round(
|
||||
Factorial::fact($numObjs + $numInSet - 1) / Factorial::fact($numObjs - 1)
|
||||
Factorial::fact($numObjs + $numInSet - 1) / Factorial::fact($numObjs - 1) // @phpstan-ignore-line
|
||||
) / Factorial::fact($numInSet);
|
||||
}
|
||||
}
|
||||
|
@@ -5,6 +5,7 @@ namespace PhpOffice\PhpSpreadsheet\Calculation\MathTrig;
|
||||
use PhpOffice\PhpSpreadsheet\Calculation\ArrayEnabled;
|
||||
use PhpOffice\PhpSpreadsheet\Calculation\Exception;
|
||||
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
|
||||
use PhpOffice\PhpSpreadsheet\Calculation\Information\ExcelError;
|
||||
use PhpOffice\PhpSpreadsheet\Calculation\Statistical;
|
||||
|
||||
class Factorial
|
||||
@@ -120,6 +121,6 @@ class Factorial
|
||||
|
||||
$summer = self::fact($summer);
|
||||
|
||||
return $summer / $divisor;
|
||||
return is_numeric($summer) ? ($summer / $divisor) : ExcelError::VALUE();
|
||||
}
|
||||
}
|
||||
|
@@ -19,7 +19,7 @@ class IntClass
|
||||
*
|
||||
* @param array|float $number Number to cast to an integer, or can be an array of numbers
|
||||
*
|
||||
* @return array|string Integer value, or a string containing an error
|
||||
* @return array|int|string Integer value, or a string containing an error
|
||||
* If an array of numbers is passed as the argument, then the returned result will also be an array
|
||||
* with the same dimensions
|
||||
*/
|
||||
|
@@ -15,8 +15,6 @@ use PhpOffice\PhpSpreadsheet\Calculation\Statistical\Variances;
|
||||
|
||||
/**
|
||||
* @deprecated 1.18.0
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
class Statistical
|
||||
{
|
||||
@@ -953,7 +951,7 @@ class Statistical
|
||||
*
|
||||
* @param mixed $args Data range and criterias
|
||||
*
|
||||
* @return float
|
||||
* @return null|float|string
|
||||
*/
|
||||
public static function MAXIFS(...$args)
|
||||
{
|
||||
@@ -1038,7 +1036,7 @@ class Statistical
|
||||
*
|
||||
* @param mixed $args Data range and criterias
|
||||
*
|
||||
* @return float
|
||||
* @return null|float|string
|
||||
*/
|
||||
public static function MINIFS(...$args)
|
||||
{
|
||||
@@ -1728,7 +1726,7 @@ class Statistical
|
||||
* Use the zTest() method in the Statistical\Distributions\StandardNormal class instead
|
||||
* @see Statistical\Distributions\StandardNormal::zTest()
|
||||
*
|
||||
* @param float $dataSet
|
||||
* @param mixed $dataSet
|
||||
* @param float $m0 Alpha Parameter
|
||||
* @param float $sigma Beta Parameter
|
||||
*
|
||||
|
@@ -196,7 +196,7 @@ class Averages extends AggregateBase
|
||||
return $returnValue;
|
||||
}
|
||||
|
||||
protected static function filterArguments($args)
|
||||
protected static function filterArguments(array $args): array
|
||||
{
|
||||
return array_filter(
|
||||
$args,
|
||||
@@ -207,11 +207,13 @@ class Averages extends AggregateBase
|
||||
);
|
||||
}
|
||||
|
||||
//
|
||||
// Special variant of array_count_values that isn't limited to strings and integers,
|
||||
// but can work with floating point numbers as values
|
||||
//
|
||||
private static function modeCalc($data)
|
||||
/**
|
||||
* Special variant of array_count_values that isn't limited to strings and integers,
|
||||
* but can work with floating point numbers as values.
|
||||
*
|
||||
* @return float|string
|
||||
*/
|
||||
private static function modeCalc(array $data)
|
||||
{
|
||||
$frequencyArray = [];
|
||||
$index = 0;
|
||||
|
@@ -187,7 +187,7 @@ class Conditional
|
||||
* @param mixed $sumRange
|
||||
* @param mixed $condition
|
||||
*
|
||||
* @return float|string
|
||||
* @return null|float|string
|
||||
*/
|
||||
public static function SUMIF($range, $condition, $sumRange = [])
|
||||
{
|
||||
@@ -223,6 +223,7 @@ class Conditional
|
||||
return DSum::evaluate($database, self::VALUE_COLUMN_NAME, $conditions);
|
||||
}
|
||||
|
||||
/** @param array $args */
|
||||
private static function buildConditionSet(...$args): array
|
||||
{
|
||||
$conditions = self::buildConditions(1, ...$args);
|
||||
@@ -231,6 +232,7 @@ class Conditional
|
||||
return array_map(/** @scrutinizer ignore-type */ null, ...$conditions);
|
||||
}
|
||||
|
||||
/** @param array $args */
|
||||
private static function buildConditionSetForValueRange(...$args): array
|
||||
{
|
||||
$conditions = self::buildConditions(2, ...$args);
|
||||
@@ -247,6 +249,7 @@ class Conditional
|
||||
return array_map(/** @scrutinizer ignore-type */ null, ...$conditions);
|
||||
}
|
||||
|
||||
/** @param array $args */
|
||||
private static function buildConditions(int $startOffset, ...$args): array
|
||||
{
|
||||
$conditions = [];
|
||||
@@ -261,6 +264,7 @@ class Conditional
|
||||
return $conditions;
|
||||
}
|
||||
|
||||
/** @param array $args */
|
||||
private static function buildDatabase(...$args): array
|
||||
{
|
||||
$database = [];
|
||||
@@ -268,6 +272,7 @@ class Conditional
|
||||
return self::buildDataSet(0, $database, ...$args);
|
||||
}
|
||||
|
||||
/** @param array $args */
|
||||
private static function buildDatabaseWithValueRange(...$args): array
|
||||
{
|
||||
$database = [];
|
||||
@@ -279,6 +284,7 @@ class Conditional
|
||||
return self::buildDataSet(1, $database, ...$args);
|
||||
}
|
||||
|
||||
/** @param array $args */
|
||||
private static function buildDataSet(int $startOffset, array $database, ...$args): array
|
||||
{
|
||||
$pairCount = 1;
|
||||
|
@@ -184,10 +184,13 @@ class Beta
|
||||
}
|
||||
|
||||
// Function cache for logBeta function
|
||||
/** @var float */
|
||||
private static $logBetaCacheP = 0.0;
|
||||
|
||||
/** @var float */
|
||||
private static $logBetaCacheQ = 0.0;
|
||||
|
||||
/** @var float */
|
||||
private static $logBetaCacheResult = 0.0;
|
||||
|
||||
/**
|
||||
|
@@ -11,8 +11,6 @@ class ChiSquared
|
||||
{
|
||||
use ArrayEnabled;
|
||||
|
||||
private const MAX_ITERATIONS = 256;
|
||||
|
||||
private const EPS = 2.22e-16;
|
||||
|
||||
/**
|
||||
@@ -197,7 +195,7 @@ class ChiSquared
|
||||
$rows = count($actual);
|
||||
$actual = Functions::flattenArray($actual);
|
||||
$expected = Functions::flattenArray($expected);
|
||||
$columns = count($actual) / $rows;
|
||||
$columns = intdiv(count($actual), $rows);
|
||||
|
||||
$countActuals = count($actual);
|
||||
$countExpected = count($expected);
|
||||
@@ -261,12 +259,12 @@ class ChiSquared
|
||||
return $chi2;
|
||||
}
|
||||
|
||||
private static function pchisq($chi2, $degrees)
|
||||
private static function pchisq(float $chi2, int $degrees): float
|
||||
{
|
||||
return self::gammp($degrees, 0.5 * $chi2);
|
||||
}
|
||||
|
||||
private static function gammp($n, $x)
|
||||
private static function gammp(int $n, float $x): float
|
||||
{
|
||||
if ($x < 0.5 * $n + 1) {
|
||||
return self::gser($n, $x);
|
||||
@@ -279,7 +277,7 @@ class ChiSquared
|
||||
// series representation. Algorithm from numerical recipe.
|
||||
// Assume that n is a positive integer and x>0, won't check arguments.
|
||||
// Relative error controlled by the eps parameter
|
||||
private static function gser($n, $x)
|
||||
private static function gser(int $n, float $x): float
|
||||
{
|
||||
/** @var float */
|
||||
$gln = Gamma::ln($n / 2);
|
||||
@@ -303,7 +301,7 @@ class ChiSquared
|
||||
// its continued fraction representation. Algorithm from numerical recipe.
|
||||
// Assume that n is a postive integer and x>0, won't check arguments.
|
||||
// Relative error controlled by the eps parameter
|
||||
private static function gcf($n, $x)
|
||||
private static function gcf(int $n, float $x): float
|
||||
{
|
||||
/** @var float */
|
||||
$gln = Gamma::ln($n / 2);
|
||||
|
@@ -17,6 +17,7 @@ abstract class GammaBase
|
||||
|
||||
private const MAX_ITERATIONS = 256;
|
||||
|
||||
/** @return float|string */
|
||||
protected static function calculateDistribution(float $value, float $a, float $b, bool $cumulative)
|
||||
{
|
||||
if ($cumulative) {
|
||||
@@ -26,6 +27,7 @@ abstract class GammaBase
|
||||
return (1 / ($b ** $a * self::gammaValue($a))) * $value ** ($a - 1) * exp(0 - ($value / $b));
|
||||
}
|
||||
|
||||
/** @return float|string */
|
||||
protected static function calculateInverse(float $probability, float $alpha, float $beta)
|
||||
{
|
||||
$xLo = 0;
|
||||
@@ -38,6 +40,9 @@ abstract class GammaBase
|
||||
while ((abs($dx) > Functions::PRECISION) && (++$i <= self::MAX_ITERATIONS)) {
|
||||
// Apply Newton-Raphson step
|
||||
$result = self::calculateDistribution($x, $alpha, $beta, true);
|
||||
if (!is_float($result)) {
|
||||
return ExcelError::NA();
|
||||
}
|
||||
$error = $result - $probability;
|
||||
|
||||
if ($error == 0.0) {
|
||||
@@ -50,6 +55,9 @@ abstract class GammaBase
|
||||
|
||||
$pdf = self::calculateDistribution($x, $alpha, $beta, false);
|
||||
// Avoid division by zero
|
||||
if (!is_float($pdf)) {
|
||||
return ExcelError::NA();
|
||||
}
|
||||
if ($pdf !== 0.0) {
|
||||
$dx = $error / $pdf;
|
||||
$xNew = $x - $dx;
|
||||
@@ -209,8 +217,10 @@ abstract class GammaBase
|
||||
private const PNT68 = 0.6796875;
|
||||
|
||||
// Function cache for logGamma
|
||||
/** @var float */
|
||||
private static $logGammaCacheResult = 0.0;
|
||||
|
||||
/** @var float */
|
||||
private static $logGammaCacheX = 0.0;
|
||||
|
||||
/**
|
||||
@@ -292,7 +302,7 @@ abstract class GammaBase
|
||||
return $res;
|
||||
}
|
||||
|
||||
private static function logGamma1(float $y)
|
||||
private static function logGamma1(float $y): float
|
||||
{
|
||||
// ---------------------
|
||||
// EPS .LT. X .LE. 1.5
|
||||
@@ -325,7 +335,7 @@ abstract class GammaBase
|
||||
return $corr + $xm2 * (self::LG_D2 + $xm2 * ($xnum / $xden));
|
||||
}
|
||||
|
||||
private static function logGamma2(float $y)
|
||||
private static function logGamma2(float $y): float
|
||||
{
|
||||
// ---------------------
|
||||
// 1.5 .LT. X .LE. 4.0
|
||||
@@ -341,7 +351,7 @@ abstract class GammaBase
|
||||
return $xm2 * (self::LG_D2 + $xm2 * ($xnum / $xden));
|
||||
}
|
||||
|
||||
protected static function logGamma3(float $y)
|
||||
protected static function logGamma3(float $y): float
|
||||
{
|
||||
// ----------------------
|
||||
// 4.0 .LT. X .LE. 12.0
|
||||
@@ -357,7 +367,7 @@ abstract class GammaBase
|
||||
return self::LG_D4 + $xm4 * ($xnum / $xden);
|
||||
}
|
||||
|
||||
protected static function logGamma4(float $y)
|
||||
protected static function logGamma4(float $y): float
|
||||
{
|
||||
// ---------------------------------
|
||||
// Evaluate for argument .GE. 12.0
|
||||
|
@@ -9,6 +9,7 @@ class NewtonRaphson
|
||||
{
|
||||
private const MAX_ITERATIONS = 256;
|
||||
|
||||
/** @var callable */
|
||||
protected $callback;
|
||||
|
||||
public function __construct(callable $callback)
|
||||
@@ -16,6 +17,7 @@ class NewtonRaphson
|
||||
$this->callback = $callback;
|
||||
}
|
||||
|
||||
/** @return float|string */
|
||||
public function execute(float $probability)
|
||||
{
|
||||
$xLo = 100;
|
||||
|
@@ -104,7 +104,7 @@ class Normal
|
||||
* email : nickersonm@yahoo.com
|
||||
*
|
||||
*/
|
||||
private static function inverseNcdf($p)
|
||||
private static function inverseNcdf(float $p): float
|
||||
{
|
||||
// Inverse ncdf approximation by Peter J. Acklam, implementation adapted to
|
||||
// PHP by Michael Nickerson, using Dr. Thomas Ziegler's C implementation as
|
||||
|
@@ -146,6 +146,8 @@ class StandardNormal
|
||||
}
|
||||
$n = count($dataSet);
|
||||
|
||||
return 1 - self::cumulative((Averages::average($dataSet) - $m0) / ($sigma / sqrt($n)));
|
||||
$sub1 = Averages::average($dataSet);
|
||||
|
||||
return is_numeric($sub1) ? (1 - self::cumulative(($sub1 - $m0) / ($sigma / sqrt($n)))) : $sub1;
|
||||
}
|
||||
}
|
||||
|
@@ -11,8 +11,6 @@ class StudentT
|
||||
{
|
||||
use ArrayEnabled;
|
||||
|
||||
private const MAX_ITERATIONS = 256;
|
||||
|
||||
/**
|
||||
* TDIST.
|
||||
*
|
||||
|
@@ -4,6 +4,11 @@ namespace PhpOffice\PhpSpreadsheet\Calculation\Statistical;
|
||||
|
||||
abstract class MaxMinBase
|
||||
{
|
||||
/**
|
||||
* @param mixed $value
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
protected static function datatypeAdjustmentAllowStrings($value)
|
||||
{
|
||||
if (is_bool($value)) {
|
||||
|
@@ -3,6 +3,7 @@
|
||||
namespace PhpOffice\PhpSpreadsheet\Calculation\Statistical;
|
||||
|
||||
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
|
||||
use PhpOffice\PhpSpreadsheet\Calculation\Information\ErrorValue;
|
||||
|
||||
class Maximum extends MaxMinBase
|
||||
{
|
||||
@@ -26,6 +27,11 @@ class Maximum extends MaxMinBase
|
||||
// Loop through arguments
|
||||
$aArgs = Functions::flattenArray($args);
|
||||
foreach ($aArgs as $arg) {
|
||||
if (ErrorValue::isError($arg)) {
|
||||
$returnValue = $arg;
|
||||
|
||||
break;
|
||||
}
|
||||
// Is it a numeric value?
|
||||
if ((is_numeric($arg)) && (!is_string($arg))) {
|
||||
if (($returnValue === null) || ($arg > $returnValue)) {
|
||||
@@ -60,6 +66,11 @@ class Maximum extends MaxMinBase
|
||||
// Loop through arguments
|
||||
$aArgs = Functions::flattenArray($args);
|
||||
foreach ($aArgs as $arg) {
|
||||
if (ErrorValue::isError($arg)) {
|
||||
$returnValue = $arg;
|
||||
|
||||
break;
|
||||
}
|
||||
// Is it a numeric value?
|
||||
if ((is_numeric($arg)) || (is_bool($arg)) || ((is_string($arg) && ($arg != '')))) {
|
||||
$arg = self::datatypeAdjustmentAllowStrings($arg);
|
||||
|
@@ -3,6 +3,7 @@
|
||||
namespace PhpOffice\PhpSpreadsheet\Calculation\Statistical;
|
||||
|
||||
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
|
||||
use PhpOffice\PhpSpreadsheet\Calculation\Information\ErrorValue;
|
||||
|
||||
class Minimum extends MaxMinBase
|
||||
{
|
||||
@@ -26,6 +27,11 @@ class Minimum extends MaxMinBase
|
||||
// Loop through arguments
|
||||
$aArgs = Functions::flattenArray($args);
|
||||
foreach ($aArgs as $arg) {
|
||||
if (ErrorValue::isError($arg)) {
|
||||
$returnValue = $arg;
|
||||
|
||||
break;
|
||||
}
|
||||
// Is it a numeric value?
|
||||
if ((is_numeric($arg)) && (!is_string($arg))) {
|
||||
if (($returnValue === null) || ($arg < $returnValue)) {
|
||||
@@ -60,6 +66,11 @@ class Minimum extends MaxMinBase
|
||||
// Loop through arguments
|
||||
$aArgs = Functions::flattenArray($args);
|
||||
foreach ($aArgs as $arg) {
|
||||
if (ErrorValue::isError($arg)) {
|
||||
$returnValue = $arg;
|
||||
|
||||
break;
|
||||
}
|
||||
// Is it a numeric value?
|
||||
if ((is_numeric($arg)) || (is_bool($arg)) || ((is_string($arg) && ($arg != '')))) {
|
||||
$arg = self::datatypeAdjustmentAllowStrings($arg);
|
||||
|
@@ -110,7 +110,7 @@ class Percentiles
|
||||
$pos += (($value - $valueSet[$pos]) / ($testValue - $valueSet[$pos]));
|
||||
}
|
||||
|
||||
return round($pos / $valueAdjustor, $significance);
|
||||
return round(((float) $pos) / $valueAdjustor, $significance);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -184,7 +184,7 @@ class Percentiles
|
||||
return ++$pos;
|
||||
}
|
||||
|
||||
protected static function percentileFilterValues(array $dataSet)
|
||||
protected static function percentileFilterValues(array $dataSet): array
|
||||
{
|
||||
return array_filter(
|
||||
$dataSet,
|
||||
@@ -194,7 +194,7 @@ class Percentiles
|
||||
);
|
||||
}
|
||||
|
||||
protected static function rankFilterValues(array $dataSet)
|
||||
protected static function rankFilterValues(array $dataSet): array
|
||||
{
|
||||
return array_filter(
|
||||
$dataSet,
|
||||
|
@@ -46,7 +46,16 @@ class Permutations
|
||||
if ($numObjs < $numInSet) {
|
||||
return ExcelError::NAN();
|
||||
}
|
||||
$result = round(MathTrig\Factorial::fact($numObjs) / MathTrig\Factorial::fact($numObjs - $numInSet));
|
||||
$result1 = MathTrig\Factorial::fact($numObjs);
|
||||
if (is_string($result1)) {
|
||||
return $result1;
|
||||
}
|
||||
$result2 = MathTrig\Factorial::fact($numObjs - $numInSet);
|
||||
if (is_string($result2)) {
|
||||
return $result2;
|
||||
}
|
||||
// phpstan thinks result1 and result2 can be arrays; they can't.
|
||||
$result = round($result1 / $result2); // @phpstan-ignore-line
|
||||
|
||||
return IntOrFloat::evaluate($result);
|
||||
}
|
||||
|
@@ -6,6 +6,11 @@ use PhpOffice\PhpSpreadsheet\Calculation\Functions;
|
||||
|
||||
abstract class VarianceBase
|
||||
{
|
||||
/**
|
||||
* @param mixed $value
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
protected static function datatypeAdjustmentAllowStrings($value)
|
||||
{
|
||||
if (is_bool($value)) {
|
||||
@@ -17,6 +22,11 @@ abstract class VarianceBase
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $value
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
protected static function datatypeAdjustmentBooleans($value)
|
||||
{
|
||||
if (is_bool($value) && (Functions::getCompatibilityMode() == Functions::COMPATIBILITY_OPENOFFICE)) {
|
||||
|
@@ -8,6 +8,8 @@ interface AddressRange
|
||||
|
||||
public const MAX_COLUMN = 'XFD';
|
||||
|
||||
public const MAX_COLUMN_INT = 16384;
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
|
@@ -198,6 +198,7 @@ class Cell
|
||||
*/
|
||||
protected static function updateIfCellIsTableHeader(Worksheet $workSheet, self $cell, $oldValue, $newValue): void
|
||||
{
|
||||
// var_dump('=>', $oldValue, $newValue);
|
||||
if (StringHelper::strToLower($oldValue ?? '') === StringHelper::strToLower($newValue ?? '')) {
|
||||
return;
|
||||
}
|
||||
@@ -365,14 +366,14 @@ class Cell
|
||||
{
|
||||
if ($this->dataType === DataType::TYPE_FORMULA) {
|
||||
try {
|
||||
$index = $this->getWorksheet()->getParent()->getActiveSheetIndex();
|
||||
$index = $this->getWorksheet()->getParentOrThrow()->getActiveSheetIndex();
|
||||
$selected = $this->getWorksheet()->getSelectedCells();
|
||||
$result = Calculation::getInstance(
|
||||
$this->getWorksheet()->getParent()
|
||||
)->calculateCellValue($this, $resetLog);
|
||||
$result = $this->convertDateTimeInt($result);
|
||||
$this->getWorksheet()->setSelectedCells($selected);
|
||||
$this->getWorksheet()->getParent()->setActiveSheetIndex($index);
|
||||
$this->getWorksheet()->getParentOrThrow()->setActiveSheetIndex($index);
|
||||
// We don't yet handle array returns
|
||||
if (is_array($result)) {
|
||||
while (is_array($result)) {
|
||||
|
@@ -263,7 +263,7 @@ abstract class Coordinate
|
||||
/**
|
||||
* Column index from string.
|
||||
*
|
||||
* @param string $columnAddress eg 'A'
|
||||
* @param ?string $columnAddress eg 'A'
|
||||
*
|
||||
* @return int Column index (A = 1)
|
||||
*/
|
||||
@@ -273,6 +273,7 @@ abstract class Coordinate
|
||||
// caching using a static within the method is faster than a class static,
|
||||
// though it's additional memory overhead
|
||||
static $indexCache = [];
|
||||
$columnAddress = $columnAddress ?? '';
|
||||
|
||||
if (isset($indexCache[$columnAddress])) {
|
||||
return $indexCache[$columnAddress];
|
||||
|
@@ -116,8 +116,7 @@ class CellReferenceHelper
|
||||
|
||||
protected function updateColumnReference(int $newColumnIndex, string $absoluteColumn): string
|
||||
{
|
||||
$newColumn = Coordinate::stringFromColumnIndex($newColumnIndex + $this->numberOfColumns);
|
||||
$newColumn = ($newColumn > AddressRange::MAX_COLUMN) ? AddressRange::MAX_COLUMN : $newColumn;
|
||||
$newColumn = Coordinate::stringFromColumnIndex(min($newColumnIndex + $this->numberOfColumns, AddressRange::MAX_COLUMN_INT));
|
||||
|
||||
return $absoluteColumn . $newColumn;
|
||||
}
|
||||
|
@@ -18,7 +18,7 @@ abstract class DefinedName
|
||||
/**
|
||||
* Worksheet on which the defined name can be resolved.
|
||||
*
|
||||
* @var Worksheet
|
||||
* @var ?Worksheet
|
||||
*/
|
||||
protected $worksheet;
|
||||
|
||||
@@ -39,7 +39,7 @@ abstract class DefinedName
|
||||
/**
|
||||
* Scope.
|
||||
*
|
||||
* @var Worksheet
|
||||
* @var ?Worksheet
|
||||
*/
|
||||
protected $scope;
|
||||
|
||||
@@ -141,17 +141,19 @@ abstract class DefinedName
|
||||
|
||||
// Re-attach
|
||||
if ($this->worksheet !== null) {
|
||||
$this->worksheet->getParent()->removeNamedRange($this->name, $this->worksheet);
|
||||
$this->worksheet->getParentOrThrow()->removeNamedRange($this->name, $this->worksheet);
|
||||
}
|
||||
$this->name = $name;
|
||||
|
||||
if ($this->worksheet !== null) {
|
||||
$this->worksheet->getParent()->addNamedRange($this);
|
||||
$this->worksheet->getParentOrThrow()->addDefinedName($this);
|
||||
}
|
||||
|
||||
// New title
|
||||
$newTitle = $this->name;
|
||||
ReferenceHelper::getInstance()->updateNamedFormulae($this->worksheet->getParent(), $oldTitle, $newTitle);
|
||||
if ($this->worksheet !== null) {
|
||||
// New title
|
||||
$newTitle = $this->name;
|
||||
ReferenceHelper::getInstance()->updateNamedFormulae($this->worksheet->getParentOrThrow(), $oldTitle, $newTitle);
|
||||
}
|
||||
}
|
||||
|
||||
return $this;
|
||||
@@ -247,13 +249,13 @@ abstract class DefinedName
|
||||
if ($sheetName === '') {
|
||||
$worksheet2 = $worksheet;
|
||||
} else {
|
||||
$worksheet2 = $worksheet->getParent()->getSheetByName($sheetName);
|
||||
$worksheet2 = $worksheet->getParentOrThrow()->getSheetByName($sheetName);
|
||||
if ($worksheet2 === null) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
return $worksheet->getParent()->getDefinedName($definedName, $worksheet2);
|
||||
return $worksheet->getParentOrThrow()->getDefinedName($definedName, $worksheet2);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -88,7 +88,9 @@ abstract class IOFactory
|
||||
* @param string $filename The name of the spreadsheet file
|
||||
* @param int $flags the optional second parameter flags may be used to identify specific elements
|
||||
* that should be loaded, but which won't be loaded by default, using these values:
|
||||
* IReader::LOAD_WITH_CHARTS - Include any charts that are defined in the loaded file
|
||||
* IReader::LOAD_WITH_CHARTS - Include any charts that are defined in the loaded file.
|
||||
* IReader::READ_DATA_ONLY - Read cell values only, not formatting or merge structure.
|
||||
* IReader::IGNORE_EMPTY_CELLS - Don't load empty cells into the model.
|
||||
* @param string[] $readers An array of Readers to use to identify the file type. By default, load() will try
|
||||
* all possible Readers until it finds a match; but this allows you to pass in a
|
||||
* list of Readers so it will only try the subset that you specify here.
|
||||
|
@@ -147,7 +147,7 @@ abstract class BaseReader implements IReader
|
||||
if (((bool) ($flags & self::READ_DATA_ONLY)) === true) {
|
||||
$this->setReadDataOnly(true);
|
||||
}
|
||||
if (((bool) ($flags & self::SKIP_EMPTY_CELLS)) === true) {
|
||||
if (((bool) ($flags & self::SKIP_EMPTY_CELLS) || (bool) ($flags & self::IGNORE_EMPTY_CELLS)) === true) {
|
||||
$this->setReadEmptyCells(false);
|
||||
}
|
||||
}
|
||||
|
@@ -9,6 +9,7 @@ interface IReader
|
||||
public const READ_DATA_ONLY = 2;
|
||||
|
||||
public const SKIP_EMPTY_CELLS = 4;
|
||||
public const IGNORE_EMPTY_CELLS = 4;
|
||||
|
||||
/**
|
||||
* IReader constructor.
|
||||
@@ -22,7 +23,8 @@ interface IReader
|
||||
|
||||
/**
|
||||
* Read data only?
|
||||
* If this is true, then the Reader will only read data values for cells, it will not read any formatting information.
|
||||
* If this is true, then the Reader will only read data values for cells, it will not read any formatting
|
||||
* or structural information (like merges).
|
||||
* If false (the default) it will read data and formatting.
|
||||
*
|
||||
* @return bool
|
||||
@@ -31,7 +33,8 @@ interface IReader
|
||||
|
||||
/**
|
||||
* Set read data only
|
||||
* Set to true, to advise the Reader only to read data values for cells, and to ignore any formatting information.
|
||||
* Set to true, to advise the Reader only to read data values for cells, and to ignore any formatting
|
||||
* or structural information (like merges).
|
||||
* Set to false (the default) to advise the Reader to read both data and formatting for cells.
|
||||
*
|
||||
* @param bool $readDataOnly
|
||||
@@ -62,9 +65,9 @@ interface IReader
|
||||
|
||||
/**
|
||||
* Read charts in workbook?
|
||||
* If this is true, then the Reader will include any charts that exist in the workbook.
|
||||
* Note that a ReadDataOnly value of false overrides, and charts won't be read regardless of the IncludeCharts value.
|
||||
* If false (the default) it will ignore any charts defined in the workbook file.
|
||||
* If this is true, then the Reader will include any charts that exist in the workbook.
|
||||
* Note that a ReadDataOnly value of false overrides, and charts won't be read regardless of the IncludeCharts value.
|
||||
* If false (the default) it will ignore any charts defined in the workbook file.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
@@ -72,9 +75,9 @@ interface IReader
|
||||
|
||||
/**
|
||||
* Set read charts in workbook
|
||||
* Set to true, to advise the Reader to include any charts that exist in the workbook.
|
||||
* Note that a ReadDataOnly value of false overrides, and charts won't be read regardless of the IncludeCharts value.
|
||||
* Set to false (the default) to discard charts.
|
||||
* Set to true, to advise the Reader to include any charts that exist in the workbook.
|
||||
* Note that a ReadDataOnly value of false overrides, and charts won't be read regardless of the IncludeCharts value.
|
||||
* Set to false (the default) to discard charts.
|
||||
*
|
||||
* @param bool $includeCharts
|
||||
*
|
||||
|
@@ -3211,10 +3211,10 @@ class Xls extends BaseReader
|
||||
for ($i = 0; $i < $nm; ++$i) {
|
||||
$c = self::getUInt2d($recordData, 2 + 6 * $i);
|
||||
$rf = self::getUInt2d($recordData, 2 + 6 * $i + 2);
|
||||
$rl = self::getUInt2d($recordData, 2 + 6 * $i + 4);
|
||||
//$rl = self::getUInt2d($recordData, 2 + 6 * $i + 4);
|
||||
|
||||
// not sure why two row indexes are necessary?
|
||||
$this->phpSheet->setBreak([$c + 1, $rf], Worksheet::BREAK_COLUMN);
|
||||
$this->phpSheet->setBreak([$c + 1, ($rf > 0) ? $rf : 1], Worksheet::BREAK_COLUMN);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -122,9 +122,12 @@ class Xlsx extends BaseReader
|
||||
return is_array($value) ? $value : [];
|
||||
}
|
||||
|
||||
private function loadZip(string $filename, string $ns = ''): SimpleXMLElement
|
||||
private function loadZip(string $filename, string $ns = '', bool $replaceUnclosedBr = false): SimpleXMLElement
|
||||
{
|
||||
$contents = $this->getFromZipArchive($this->zip, $filename);
|
||||
if ($replaceUnclosedBr) {
|
||||
$contents = str_replace('<br>', '<br/>', $contents);
|
||||
}
|
||||
$rels = simplexml_load_string(
|
||||
$this->securityScanner->scan($contents),
|
||||
'SimpleXMLElement',
|
||||
@@ -1029,6 +1032,7 @@ class Xlsx extends BaseReader
|
||||
|
||||
// later we will remove from it real vmlComments
|
||||
$unparsedVmlDrawings = $vmlComments;
|
||||
$vmlDrawingContents = [];
|
||||
|
||||
// Loop through VML comments
|
||||
foreach ($vmlComments as $relName => $relPath) {
|
||||
@@ -1037,7 +1041,7 @@ class Xlsx extends BaseReader
|
||||
|
||||
try {
|
||||
// no namespace okay - processed with Xpath
|
||||
$vmlCommentsFile = $this->loadZip($relPath, '');
|
||||
$vmlCommentsFile = $this->loadZip($relPath, '', true);
|
||||
$vmlCommentsFile->registerXPathNamespace('v', Namespaces::URN_VML);
|
||||
} catch (Throwable $ex) {
|
||||
//Ignore unparsable vmlDrawings. Later they will be moved from $unparsedVmlDrawings to $unparsedLoadedData
|
||||
@@ -1047,6 +1051,7 @@ class Xlsx extends BaseReader
|
||||
// Locate VML drawings image relations
|
||||
$drowingImages = [];
|
||||
$VMLDrawingsRelations = dirname($relPath) . '/_rels/' . basename($relPath) . '.rels';
|
||||
$vmlDrawingContents[$relName] = $this->securityScanner->scan($this->getFromZipArchive($zip, $relPath));
|
||||
if ($zip->locateName($VMLDrawingsRelations)) {
|
||||
$relsVMLDrawing = $this->loadZip($VMLDrawingsRelations, Namespaces::RELATIONSHIPS);
|
||||
foreach ($relsVMLDrawing->Relationship as $elex) {
|
||||
@@ -1519,6 +1524,14 @@ class Xlsx extends BaseReader
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($xmlSheet->legacyDrawing && !$this->readDataOnly) {
|
||||
foreach ($xmlSheet->legacyDrawing as $drawing) {
|
||||
$drawingRelId = (string) self::getArrayItem(self::getAttributes($drawing, $xmlNamespaceBase), 'id');
|
||||
if (isset($vmlDrawingContents[$drawingRelId])) {
|
||||
$unparsedLoadedData['sheets'][$docSheet->getCodeName()]['legacyDrawing'] = $vmlDrawingContents[$drawingRelId];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// unparsed drawing AlternateContent
|
||||
$xmlAltDrawing = $this->loadZip((string) $fileDrawing, Namespaces::COMPATIBILITY);
|
||||
|
@@ -550,7 +550,7 @@ class ReferenceHelper
|
||||
}
|
||||
|
||||
// Update workbook: define names
|
||||
if (count($worksheet->getParent()->getDefinedNames()) > 0) {
|
||||
if (count($worksheet->getParentOrThrow()->getDefinedNames()) > 0) {
|
||||
$this->updateDefinedNames($worksheet, $beforeCellAddress, $numberOfColumns, $numberOfRows);
|
||||
}
|
||||
|
||||
@@ -905,7 +905,7 @@ class ReferenceHelper
|
||||
|
||||
private function updateDefinedNames(Worksheet $worksheet, string $beforeCellAddress, int $numberOfColumns, int $numberOfRows): void
|
||||
{
|
||||
foreach ($worksheet->getParent()->getDefinedNames() as $definedName) {
|
||||
foreach ($worksheet->getParentOrThrow()->getDefinedNames() as $definedName) {
|
||||
if ($definedName->isFormula() === false) {
|
||||
$this->updateNamedRange($definedName, $worksheet, $beforeCellAddress, $numberOfColumns, $numberOfRows);
|
||||
} else {
|
||||
|
@@ -1,16 +0,0 @@
|
||||
Mar 1, 2005 11:15 AST by PM
|
||||
|
||||
+ For consistency, renamed Math.php to Maths.java, utils to util,
|
||||
tests to test, docs to doc -
|
||||
|
||||
+ Removed conditional logic from top of Matrix class.
|
||||
|
||||
+ Switched to using hypo function in Maths.php for all php-hypot calls.
|
||||
NOTE TO SELF: Need to make sure that all decompositions have been
|
||||
switched over to using the bundled hypo.
|
||||
|
||||
Feb 25, 2005 at 10:00 AST by PM
|
||||
|
||||
+ Recommend using simpler Error.php instead of JAMA_Error.php but
|
||||
can be persuaded otherwise.
|
||||
|
@@ -1,286 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace PhpOffice\PhpSpreadsheet\Shared\JAMA;
|
||||
|
||||
use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalculationException;
|
||||
|
||||
/**
|
||||
* For an m-by-n matrix A with m >= n, the LU decomposition is an m-by-n
|
||||
* unit lower triangular matrix L, an n-by-n upper triangular matrix U,
|
||||
* and a permutation vector piv of length m so that A(piv,:) = L*U.
|
||||
* If m < n, then L is m-by-m and U is m-by-n.
|
||||
*
|
||||
* The LU decompostion with pivoting always exists, even if the matrix is
|
||||
* singular, so the constructor will never fail. The primary use of the
|
||||
* LU decomposition is in the solution of square systems of simultaneous
|
||||
* linear equations. This will fail if isNonsingular() returns false.
|
||||
*
|
||||
* @author Paul Meagher
|
||||
* @author Bartosz Matosiuk
|
||||
* @author Michael Bommarito
|
||||
*
|
||||
* @version 1.1
|
||||
*/
|
||||
class LUDecomposition
|
||||
{
|
||||
const MATRIX_SINGULAR_EXCEPTION = 'Can only perform operation on singular matrix.';
|
||||
const MATRIX_SQUARE_EXCEPTION = 'Mismatched Row dimension';
|
||||
|
||||
/**
|
||||
* Decomposition storage.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $LU = [];
|
||||
|
||||
/**
|
||||
* Row dimension.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
private $m;
|
||||
|
||||
/**
|
||||
* Column dimension.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
private $n;
|
||||
|
||||
/**
|
||||
* Pivot sign.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
private $pivsign;
|
||||
|
||||
/**
|
||||
* Internal storage of pivot vector.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $piv = [];
|
||||
|
||||
/**
|
||||
* LU Decomposition constructor.
|
||||
*
|
||||
* @param ?Matrix $A Rectangular matrix
|
||||
*/
|
||||
public function __construct($A)
|
||||
{
|
||||
if ($A instanceof Matrix) {
|
||||
// Use a "left-looking", dot-product, Crout/Doolittle algorithm.
|
||||
$this->LU = $A->getArray();
|
||||
$this->m = $A->getRowDimension();
|
||||
$this->n = $A->getColumnDimension();
|
||||
for ($i = 0; $i < $this->m; ++$i) {
|
||||
$this->piv[$i] = $i;
|
||||
}
|
||||
$this->pivsign = 1;
|
||||
$LUcolj = [];
|
||||
|
||||
// Outer loop.
|
||||
for ($j = 0; $j < $this->n; ++$j) {
|
||||
// Make a copy of the j-th column to localize references.
|
||||
for ($i = 0; $i < $this->m; ++$i) {
|
||||
$LUcolj[$i] = &$this->LU[$i][$j];
|
||||
}
|
||||
// Apply previous transformations.
|
||||
for ($i = 0; $i < $this->m; ++$i) {
|
||||
$LUrowi = $this->LU[$i];
|
||||
// Most of the time is spent in the following dot product.
|
||||
$kmax = min($i, $j);
|
||||
$s = 0.0;
|
||||
for ($k = 0; $k < $kmax; ++$k) {
|
||||
$s += $LUrowi[$k] * $LUcolj[$k];
|
||||
}
|
||||
$LUrowi[$j] = $LUcolj[$i] -= $s;
|
||||
}
|
||||
// Find pivot and exchange if necessary.
|
||||
$p = $j;
|
||||
for ($i = $j + 1; $i < $this->m; ++$i) {
|
||||
if (abs($LUcolj[$i]) > abs($LUcolj[$p])) {
|
||||
$p = $i;
|
||||
}
|
||||
}
|
||||
if ($p != $j) {
|
||||
for ($k = 0; $k < $this->n; ++$k) {
|
||||
$t = $this->LU[$p][$k];
|
||||
$this->LU[$p][$k] = $this->LU[$j][$k];
|
||||
$this->LU[$j][$k] = $t;
|
||||
}
|
||||
$k = $this->piv[$p];
|
||||
$this->piv[$p] = $this->piv[$j];
|
||||
$this->piv[$j] = $k;
|
||||
$this->pivsign = $this->pivsign * -1;
|
||||
}
|
||||
// Compute multipliers.
|
||||
if (($j < $this->m) && ($this->LU[$j][$j] != 0.0)) {
|
||||
for ($i = $j + 1; $i < $this->m; ++$i) {
|
||||
$this->LU[$i][$j] /= $this->LU[$j][$j];
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
throw new CalculationException(Matrix::ARGUMENT_TYPE_EXCEPTION);
|
||||
}
|
||||
}
|
||||
|
||||
// function __construct()
|
||||
|
||||
/**
|
||||
* Get lower triangular factor.
|
||||
*
|
||||
* @return Matrix Lower triangular factor
|
||||
*/
|
||||
public function getL()
|
||||
{
|
||||
$L = [];
|
||||
for ($i = 0; $i < $this->m; ++$i) {
|
||||
for ($j = 0; $j < $this->n; ++$j) {
|
||||
if ($i > $j) {
|
||||
$L[$i][$j] = $this->LU[$i][$j];
|
||||
} elseif ($i == $j) {
|
||||
$L[$i][$j] = 1.0;
|
||||
} else {
|
||||
$L[$i][$j] = 0.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new Matrix($L);
|
||||
}
|
||||
|
||||
// function getL()
|
||||
|
||||
/**
|
||||
* Get upper triangular factor.
|
||||
*
|
||||
* @return Matrix Upper triangular factor
|
||||
*/
|
||||
public function getU()
|
||||
{
|
||||
$U = [];
|
||||
for ($i = 0; $i < $this->n; ++$i) {
|
||||
for ($j = 0; $j < $this->n; ++$j) {
|
||||
if ($i <= $j) {
|
||||
$U[$i][$j] = $this->LU[$i][$j];
|
||||
} else {
|
||||
$U[$i][$j] = 0.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new Matrix($U);
|
||||
}
|
||||
|
||||
// function getU()
|
||||
|
||||
/**
|
||||
* Return pivot permutation vector.
|
||||
*
|
||||
* @return array Pivot vector
|
||||
*/
|
||||
public function getPivot()
|
||||
{
|
||||
return $this->piv;
|
||||
}
|
||||
|
||||
// function getPivot()
|
||||
|
||||
/**
|
||||
* Alias for getPivot.
|
||||
*
|
||||
* @see getPivot
|
||||
*
|
||||
* @return array Pivot vector
|
||||
*/
|
||||
public function getDoublePivot()
|
||||
{
|
||||
return $this->getPivot();
|
||||
}
|
||||
|
||||
// function getDoublePivot()
|
||||
|
||||
/**
|
||||
* Is the matrix nonsingular?
|
||||
*
|
||||
* @return bool true if U, and hence A, is nonsingular
|
||||
*/
|
||||
public function isNonsingular()
|
||||
{
|
||||
for ($j = 0; $j < $this->n; ++$j) {
|
||||
if ($this->LU[$j][$j] == 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// function isNonsingular()
|
||||
|
||||
/**
|
||||
* Count determinants.
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public function det()
|
||||
{
|
||||
if ($this->m == $this->n) {
|
||||
$d = $this->pivsign;
|
||||
for ($j = 0; $j < $this->n; ++$j) {
|
||||
$d *= $this->LU[$j][$j];
|
||||
}
|
||||
|
||||
return $d;
|
||||
}
|
||||
|
||||
throw new CalculationException(Matrix::MATRIX_DIMENSION_EXCEPTION);
|
||||
}
|
||||
|
||||
// function det()
|
||||
|
||||
/**
|
||||
* Solve A*X = B.
|
||||
*
|
||||
* @param Matrix $B a Matrix with as many rows as A and any number of columns
|
||||
*
|
||||
* @return Matrix X so that L*U*X = B(piv,:)
|
||||
*/
|
||||
public function solve(Matrix $B)
|
||||
{
|
||||
if ($B->getRowDimension() == $this->m) {
|
||||
if ($this->isNonsingular()) {
|
||||
// Copy right hand side with pivoting
|
||||
$nx = $B->getColumnDimension();
|
||||
$X = $B->getMatrix($this->piv, 0, $nx - 1);
|
||||
// Solve L*Y = B(piv,:)
|
||||
for ($k = 0; $k < $this->n; ++$k) {
|
||||
for ($i = $k + 1; $i < $this->n; ++$i) {
|
||||
for ($j = 0; $j < $nx; ++$j) {
|
||||
$X->A[$i][$j] -= $X->A[$k][$j] * $this->LU[$i][$k];
|
||||
}
|
||||
}
|
||||
}
|
||||
// Solve U*X = Y;
|
||||
for ($k = $this->n - 1; $k >= 0; --$k) {
|
||||
for ($j = 0; $j < $nx; ++$j) {
|
||||
$X->A[$k][$j] /= $this->LU[$k][$k];
|
||||
}
|
||||
for ($i = 0; $i < $k; ++$i) {
|
||||
for ($j = 0; $j < $nx; ++$j) {
|
||||
$X->A[$i][$j] -= $X->A[$k][$j] * $this->LU[$i][$k];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $X;
|
||||
}
|
||||
|
||||
throw new CalculationException(self::MATRIX_SINGULAR_EXCEPTION);
|
||||
}
|
||||
|
||||
throw new CalculationException(self::MATRIX_SQUARE_EXCEPTION);
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@@ -1,245 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace PhpOffice\PhpSpreadsheet\Shared\JAMA;
|
||||
|
||||
use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalculationException;
|
||||
|
||||
/**
|
||||
* For an m-by-n matrix A with m >= n, the QR decomposition is an m-by-n
|
||||
* orthogonal matrix Q and an n-by-n upper triangular matrix R so that
|
||||
* A = Q*R.
|
||||
*
|
||||
* The QR decompostion always exists, even if the matrix does not have
|
||||
* full rank, so the constructor will never fail. The primary use of the
|
||||
* QR decomposition is in the least squares solution of nonsquare systems
|
||||
* of simultaneous linear equations. This will fail if isFullRank()
|
||||
* returns false.
|
||||
*
|
||||
* @author Paul Meagher
|
||||
*
|
||||
* @version 1.1
|
||||
*/
|
||||
class QRDecomposition
|
||||
{
|
||||
const MATRIX_RANK_EXCEPTION = 'Can only perform operation on full-rank matrix.';
|
||||
|
||||
/**
|
||||
* Array for internal storage of decomposition.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $QR = [];
|
||||
|
||||
/**
|
||||
* Row dimension.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
private $m;
|
||||
|
||||
/**
|
||||
* Column dimension.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
private $n;
|
||||
|
||||
/**
|
||||
* Array for internal storage of diagonal of R.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $Rdiag = [];
|
||||
|
||||
/**
|
||||
* QR Decomposition computed by Householder reflections.
|
||||
*
|
||||
* @param Matrix $A Rectangular matrix
|
||||
*/
|
||||
public function __construct(Matrix $A)
|
||||
{
|
||||
// Initialize.
|
||||
$this->QR = $A->getArray();
|
||||
$this->m = $A->getRowDimension();
|
||||
$this->n = $A->getColumnDimension();
|
||||
// Main loop.
|
||||
for ($k = 0; $k < $this->n; ++$k) {
|
||||
// Compute 2-norm of k-th column without under/overflow.
|
||||
$nrm = 0.0;
|
||||
for ($i = $k; $i < $this->m; ++$i) {
|
||||
$nrm = hypo($nrm, $this->QR[$i][$k]);
|
||||
}
|
||||
if ($nrm != 0.0) {
|
||||
// Form k-th Householder vector.
|
||||
if ($this->QR[$k][$k] < 0) {
|
||||
$nrm = -$nrm;
|
||||
}
|
||||
for ($i = $k; $i < $this->m; ++$i) {
|
||||
$this->QR[$i][$k] /= $nrm;
|
||||
}
|
||||
$this->QR[$k][$k] += 1.0;
|
||||
// Apply transformation to remaining columns.
|
||||
for ($j = $k + 1; $j < $this->n; ++$j) {
|
||||
$s = 0.0;
|
||||
for ($i = $k; $i < $this->m; ++$i) {
|
||||
$s += $this->QR[$i][$k] * $this->QR[$i][$j];
|
||||
}
|
||||
$s = -$s / $this->QR[$k][$k];
|
||||
for ($i = $k; $i < $this->m; ++$i) {
|
||||
$this->QR[$i][$j] += $s * $this->QR[$i][$k];
|
||||
}
|
||||
}
|
||||
}
|
||||
$this->Rdiag[$k] = -$nrm;
|
||||
}
|
||||
}
|
||||
|
||||
// function __construct()
|
||||
|
||||
/**
|
||||
* Is the matrix full rank?
|
||||
*
|
||||
* @return bool true if R, and hence A, has full rank, else false
|
||||
*/
|
||||
public function isFullRank()
|
||||
{
|
||||
for ($j = 0; $j < $this->n; ++$j) {
|
||||
if ($this->Rdiag[$j] == 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// function isFullRank()
|
||||
|
||||
/**
|
||||
* Return the Householder vectors.
|
||||
*
|
||||
* @return Matrix Lower trapezoidal matrix whose columns define the reflections
|
||||
*/
|
||||
public function getH()
|
||||
{
|
||||
$H = [];
|
||||
for ($i = 0; $i < $this->m; ++$i) {
|
||||
for ($j = 0; $j < $this->n; ++$j) {
|
||||
if ($i >= $j) {
|
||||
$H[$i][$j] = $this->QR[$i][$j];
|
||||
} else {
|
||||
$H[$i][$j] = 0.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new Matrix($H);
|
||||
}
|
||||
|
||||
// function getH()
|
||||
|
||||
/**
|
||||
* Return the upper triangular factor.
|
||||
*
|
||||
* @return Matrix upper triangular factor
|
||||
*/
|
||||
public function getR()
|
||||
{
|
||||
$R = [];
|
||||
for ($i = 0; $i < $this->n; ++$i) {
|
||||
for ($j = 0; $j < $this->n; ++$j) {
|
||||
if ($i < $j) {
|
||||
$R[$i][$j] = $this->QR[$i][$j];
|
||||
} elseif ($i == $j) {
|
||||
$R[$i][$j] = $this->Rdiag[$i];
|
||||
} else {
|
||||
$R[$i][$j] = 0.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new Matrix($R);
|
||||
}
|
||||
|
||||
// function getR()
|
||||
|
||||
/**
|
||||
* Generate and return the (economy-sized) orthogonal factor.
|
||||
*
|
||||
* @return Matrix orthogonal factor
|
||||
*/
|
||||
public function getQ()
|
||||
{
|
||||
$Q = [];
|
||||
for ($k = $this->n - 1; $k >= 0; --$k) {
|
||||
for ($i = 0; $i < $this->m; ++$i) {
|
||||
$Q[$i][$k] = 0.0;
|
||||
}
|
||||
$Q[$k][$k] = 1.0;
|
||||
for ($j = $k; $j < $this->n; ++$j) {
|
||||
if ($this->QR[$k][$k] != 0) {
|
||||
$s = 0.0;
|
||||
for ($i = $k; $i < $this->m; ++$i) {
|
||||
$s += $this->QR[$i][$k] * $Q[$i][$j];
|
||||
}
|
||||
$s = -$s / $this->QR[$k][$k];
|
||||
for ($i = $k; $i < $this->m; ++$i) {
|
||||
$Q[$i][$j] += $s * $this->QR[$i][$k];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new Matrix($Q);
|
||||
}
|
||||
|
||||
// function getQ()
|
||||
|
||||
/**
|
||||
* Least squares solution of A*X = B.
|
||||
*
|
||||
* @param Matrix $B a Matrix with as many rows as A and any number of columns
|
||||
*
|
||||
* @return Matrix matrix that minimizes the two norm of Q*R*X-B
|
||||
*/
|
||||
public function solve(Matrix $B)
|
||||
{
|
||||
if ($B->getRowDimension() == $this->m) {
|
||||
if ($this->isFullRank()) {
|
||||
// Copy right hand side
|
||||
$nx = $B->getColumnDimension();
|
||||
$X = $B->getArray();
|
||||
// Compute Y = transpose(Q)*B
|
||||
for ($k = 0; $k < $this->n; ++$k) {
|
||||
for ($j = 0; $j < $nx; ++$j) {
|
||||
$s = 0.0;
|
||||
for ($i = $k; $i < $this->m; ++$i) {
|
||||
$s += $this->QR[$i][$k] * $X[$i][$j];
|
||||
}
|
||||
$s = -$s / $this->QR[$k][$k];
|
||||
for ($i = $k; $i < $this->m; ++$i) {
|
||||
$X[$i][$j] += $s * $this->QR[$i][$k];
|
||||
}
|
||||
}
|
||||
}
|
||||
// Solve R*X = Y;
|
||||
for ($k = $this->n - 1; $k >= 0; --$k) {
|
||||
for ($j = 0; $j < $nx; ++$j) {
|
||||
$X[$k][$j] /= $this->Rdiag[$k];
|
||||
}
|
||||
for ($i = 0; $i < $k; ++$i) {
|
||||
for ($j = 0; $j < $nx; ++$j) {
|
||||
$X[$i][$j] -= $X[$k][$j] * $this->QR[$i][$k];
|
||||
}
|
||||
}
|
||||
}
|
||||
$X = new Matrix($X);
|
||||
|
||||
return $X->getMatrix(0, $this->n - 1, 0, $nx);
|
||||
}
|
||||
|
||||
throw new CalculationException(self::MATRIX_RANK_EXCEPTION);
|
||||
}
|
||||
|
||||
throw new CalculationException(Matrix::MATRIX_DIMENSION_EXCEPTION);
|
||||
}
|
||||
}
|
@@ -1,31 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Pythagorean Theorem:.
|
||||
*
|
||||
* a = 3
|
||||
* b = 4
|
||||
* r = sqrt(square(a) + square(b))
|
||||
* r = 5
|
||||
*
|
||||
* r = sqrt(a^2 + b^2) without under/overflow.
|
||||
*
|
||||
* @param mixed $a
|
||||
* @param mixed $b
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
function hypo($a, $b)
|
||||
{
|
||||
if (abs($a) > abs($b)) {
|
||||
$r = $b / $a;
|
||||
$r = abs($a) * sqrt(1 + $r * $r);
|
||||
} elseif ($b != 0) {
|
||||
$r = $a / $b;
|
||||
$r = abs($b) * sqrt(1 + $r * $r);
|
||||
} else {
|
||||
$r = 0.0;
|
||||
}
|
||||
|
||||
return $r;
|
||||
}
|
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace PhpOffice\PhpSpreadsheet\Shared\Trend;
|
||||
|
||||
use PhpOffice\PhpSpreadsheet\Shared\JAMA\Matrix;
|
||||
use Matrix\Matrix;
|
||||
|
||||
// Phpstan and Scrutinizer seem to have legitimate complaints.
|
||||
// $this->slope is specified where an array is expected in several places.
|
||||
@@ -167,8 +167,8 @@ class PolynomialBestFit extends BestFit
|
||||
$C = $matrixA->solve($matrixB);
|
||||
|
||||
$coefficients = [];
|
||||
for ($i = 0; $i < $C->getRowDimension(); ++$i) {
|
||||
$r = $C->get($i, 0);
|
||||
for ($i = 0; $i < $C->rows; ++$i) {
|
||||
$r = $C->getValue($i + 1, 1); // row and column are origin-1
|
||||
if (abs($r) <= 10 ** (-9)) {
|
||||
$r = 0;
|
||||
}
|
||||
|
@@ -21,7 +21,7 @@ class Xls
|
||||
public static function sizeCol(Worksheet $worksheet, $col = 'A')
|
||||
{
|
||||
// default font of the workbook
|
||||
$font = $worksheet->getParent()->getDefaultStyle()->getFont();
|
||||
$font = $worksheet->getParentOrThrow()->getDefaultStyle()->getFont();
|
||||
|
||||
$columnDimensions = $worksheet->getColumnDimensions();
|
||||
|
||||
@@ -64,7 +64,7 @@ class Xls
|
||||
public static function sizeRow(Worksheet $worksheet, $row = 1)
|
||||
{
|
||||
// default font of the workbook
|
||||
$font = $worksheet->getParent()->getDefaultStyle()->getFont();
|
||||
$font = $worksheet->getParentOrThrow()->getDefaultStyle()->getFont();
|
||||
|
||||
$rowDimensions = $worksheet->getRowDimensions();
|
||||
|
||||
|
@@ -643,7 +643,7 @@ class Spreadsheet implements JsonSerializable
|
||||
}
|
||||
}
|
||||
|
||||
if ($worksheet->getParent() === null) { // @phpstan-ignore-line
|
||||
if ($worksheet->getParent() === null) {
|
||||
$worksheet->rebindParent($this);
|
||||
}
|
||||
|
||||
@@ -871,7 +871,7 @@ class Spreadsheet implements JsonSerializable
|
||||
$countCellXfs = count($this->cellXfCollection);
|
||||
|
||||
// copy all the shared cellXfs from the external workbook and append them to the current
|
||||
foreach ($worksheet->getParent()->getCellXfCollection() as $cellXf) {
|
||||
foreach ($worksheet->getParentOrThrow()->getCellXfCollection() as $cellXf) {
|
||||
$this->addCellXf(clone $cellXf);
|
||||
}
|
||||
|
||||
|
@@ -193,7 +193,7 @@ class CellMatcher
|
||||
}
|
||||
|
||||
if (!empty($matches[4])) {
|
||||
$worksheet = $this->worksheet->getParent()->getSheetByName(trim($matches[4], "'"));
|
||||
$worksheet = $this->worksheet->getParentOrThrow()->getSheetByName(trim($matches[4], "'"));
|
||||
if ($worksheet === null) {
|
||||
return $this->wrapValue(null);
|
||||
}
|
||||
|
@@ -130,7 +130,7 @@ class Style extends Supervisor
|
||||
$xfIndex = 0;
|
||||
}
|
||||
|
||||
return $activeSheet->getParent()->getCellXfByIndex($xfIndex);
|
||||
return $activeSheet->getParentOrThrow()->getCellXfByIndex($xfIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -138,7 +138,7 @@ class Style extends Supervisor
|
||||
*/
|
||||
public function getParent(): Spreadsheet
|
||||
{
|
||||
return $this->getActiveSheet()->getParent();
|
||||
return $this->getActiveSheet()->getParentOrThrow();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -372,7 +372,7 @@ class Style extends Supervisor
|
||||
$oldXfIndexes = $this->getOldXfIndexes($selectionType, $rangeStartIndexes, $rangeEndIndexes, $columnStart, $columnEnd, $styleArray);
|
||||
|
||||
// clone each of the affected styles, apply the style array, and add the new styles to the workbook
|
||||
$workbook = $this->getActiveSheet()->getParent();
|
||||
$workbook = $this->getActiveSheet()->getParentOrThrow();
|
||||
$newXfIndexes = [];
|
||||
foreach ($oldXfIndexes as $oldXfIndex => $dummy) {
|
||||
$style = $workbook->getCellXfByIndex($oldXfIndex);
|
||||
|
@@ -17,6 +17,10 @@ abstract class CellIterator implements NativeIterator
|
||||
|
||||
public const TREAT_EMPTY_STRING_AS_EMPTY_CELL = 2;
|
||||
|
||||
public const IF_NOT_EXISTS_RETURN_NULL = false;
|
||||
|
||||
public const IF_NOT_EXISTS_CREATE_NEW = true;
|
||||
|
||||
/**
|
||||
* Worksheet to iterate.
|
||||
*
|
||||
@@ -38,6 +42,14 @@ abstract class CellIterator implements NativeIterator
|
||||
*/
|
||||
protected $onlyExistingCells = false;
|
||||
|
||||
/**
|
||||
* If iterating all cells, and a cell doesn't exist, identifies whether a new cell should be created,
|
||||
* or if the iterator should return a null value.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $ifNotExists = self::IF_NOT_EXISTS_CREATE_NEW;
|
||||
|
||||
/**
|
||||
* Destructor.
|
||||
*/
|
||||
@@ -47,6 +59,16 @@ abstract class CellIterator implements NativeIterator
|
||||
$this->worksheet = $this->cellCollection = null;
|
||||
}
|
||||
|
||||
public function getIfNotExists(): bool
|
||||
{
|
||||
return $this->ifNotExists;
|
||||
}
|
||||
|
||||
public function setIfNotExists(bool $ifNotExists = self::IF_NOT_EXISTS_CREATE_NEW): void
|
||||
{
|
||||
$this->ifNotExists = $ifNotExists;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get loop only existing cells.
|
||||
*/
|
||||
@@ -56,9 +78,9 @@ abstract class CellIterator implements NativeIterator
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate start/end values for "IterateOnlyExistingCells" mode, and adjust if necessary.
|
||||
* Validate start/end values for 'IterateOnlyExistingCells' mode, and adjust if necessary.
|
||||
*/
|
||||
abstract protected function adjustForExistingOnlyRange();
|
||||
abstract protected function adjustForExistingOnlyRange(): void;
|
||||
|
||||
/**
|
||||
* Set the iterator to loop only existing cells.
|
||||
|
@@ -52,14 +52,23 @@ class Column
|
||||
*
|
||||
* @param int $startRow The row number at which to start iterating
|
||||
* @param int $endRow Optionally, the row number at which to stop iterating
|
||||
*
|
||||
* @return ColumnCellIterator
|
||||
*/
|
||||
public function getCellIterator($startRow = 1, $endRow = null)
|
||||
public function getCellIterator($startRow = 1, $endRow = null): ColumnCellIterator
|
||||
{
|
||||
return new ColumnCellIterator($this->worksheet, $this->columnIndex, $startRow, $endRow);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get row iterator. Synonym for getCellIterator().
|
||||
*
|
||||
* @param int $startRow The row number at which to start iterating
|
||||
* @param int $endRow Optionally, the row number at which to stop iterating
|
||||
*/
|
||||
public function getRowIterator($startRow = 1, $endRow = null): ColumnCellIterator
|
||||
{
|
||||
return $this->getCellIterator($startRow, $endRow);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a boolean true if the column contains no cells. By default, this means that no cell records exist in the
|
||||
* collection for this column. false will be returned otherwise.
|
||||
@@ -76,13 +85,15 @@ class Column
|
||||
* Possible Flag Values are:
|
||||
* CellIterator::TREAT_NULL_VALUE_AS_EMPTY_CELL
|
||||
* CellIterator::TREAT_EMPTY_STRING_AS_EMPTY_CELL
|
||||
* @param int $startRow The row number at which to start iterating
|
||||
* @param int $endRow Optionally, the row number at which to stop iterating
|
||||
*/
|
||||
public function isEmpty(int $definitionOfEmptyFlags = 0): bool
|
||||
public function isEmpty(int $definitionOfEmptyFlags = 0, $startRow = 1, $endRow = null): bool
|
||||
{
|
||||
$nullValueCellIsEmpty = (bool) ($definitionOfEmptyFlags & CellIterator::TREAT_NULL_VALUE_AS_EMPTY_CELL);
|
||||
$emptyStringCellIsEmpty = (bool) ($definitionOfEmptyFlags & CellIterator::TREAT_EMPTY_STRING_AS_EMPTY_CELL);
|
||||
|
||||
$cellIterator = $this->getCellIterator();
|
||||
$cellIterator = $this->getCellIterator($startRow, $endRow);
|
||||
$cellIterator->setIterateOnlyExistingCells(true);
|
||||
foreach ($cellIterator as $cell) {
|
||||
/** @scrutinizer ignore-call */
|
||||
|
@@ -128,7 +128,11 @@ class ColumnCellIterator extends CellIterator
|
||||
|
||||
return $this->cellCollection->has($cellAddress)
|
||||
? $this->cellCollection->get($cellAddress)
|
||||
: $this->worksheet->createNewCell($cellAddress);
|
||||
: (
|
||||
$this->ifNotExists === self::IF_NOT_EXISTS_CREATE_NEW
|
||||
? $this->worksheet->createNewCell($cellAddress)
|
||||
: null
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -10,7 +10,7 @@ class ColumnDimension extends Dimension
|
||||
/**
|
||||
* Column index.
|
||||
*
|
||||
* @var string
|
||||
* @var ?string
|
||||
*/
|
||||
private $columnIndex;
|
||||
|
||||
@@ -33,7 +33,7 @@ class ColumnDimension extends Dimension
|
||||
/**
|
||||
* Create a new ColumnDimension.
|
||||
*
|
||||
* @param string $index Character column index
|
||||
* @param ?string $index Character column index
|
||||
*/
|
||||
public function __construct($index = 'A')
|
||||
{
|
||||
@@ -47,7 +47,7 @@ class ColumnDimension extends Dimension
|
||||
/**
|
||||
* Get column index as string eg: 'A'.
|
||||
*/
|
||||
public function getColumnIndex(): string
|
||||
public function getColumnIndex(): ?string
|
||||
{
|
||||
return $this->columnIndex;
|
||||
}
|
||||
@@ -67,7 +67,7 @@ class ColumnDimension extends Dimension
|
||||
*/
|
||||
public function getColumnNumeric(): int
|
||||
{
|
||||
return Coordinate::columnIndexFromString($this->columnIndex);
|
||||
return Coordinate::columnIndexFromString($this->columnIndex ?? '');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -220,7 +220,7 @@ class Shadow implements IComparable
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setColor(?Color $color = null)
|
||||
public function setColor(Color $color)
|
||||
{
|
||||
$this->color = $color;
|
||||
|
||||
|
@@ -639,7 +639,7 @@ class PageSetup
|
||||
public function getPrintArea($index = 0)
|
||||
{
|
||||
if ($index == 0) {
|
||||
return $this->printArea;
|
||||
return (string) $this->printArea;
|
||||
}
|
||||
$printAreas = explode(',', (string) $this->printArea);
|
||||
if (isset($printAreas[$index - 1])) {
|
||||
|
@@ -51,14 +51,23 @@ class Row
|
||||
*
|
||||
* @param string $startColumn The column address at which to start iterating
|
||||
* @param string $endColumn Optionally, the column address at which to stop iterating
|
||||
*
|
||||
* @return RowCellIterator
|
||||
*/
|
||||
public function getCellIterator($startColumn = 'A', $endColumn = null)
|
||||
public function getCellIterator($startColumn = 'A', $endColumn = null): RowCellIterator
|
||||
{
|
||||
return new RowCellIterator($this->worksheet, $this->rowIndex, $startColumn, $endColumn);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get column iterator. Synonym for getCellIterator().
|
||||
*
|
||||
* @param string $startColumn The column address at which to start iterating
|
||||
* @param string $endColumn Optionally, the column address at which to stop iterating
|
||||
*/
|
||||
public function getColumnIterator($startColumn = 'A', $endColumn = null): RowCellIterator
|
||||
{
|
||||
return $this->getCellIterator($startColumn, $endColumn);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a boolean true if the row contains no cells. By default, this means that no cell records exist in the
|
||||
* collection for this row. false will be returned otherwise.
|
||||
@@ -75,13 +84,15 @@ class Row
|
||||
* Possible Flag Values are:
|
||||
* CellIterator::TREAT_NULL_VALUE_AS_EMPTY_CELL
|
||||
* CellIterator::TREAT_EMPTY_STRING_AS_EMPTY_CELL
|
||||
* @param string $startColumn The column address at which to start iterating
|
||||
* @param string $endColumn Optionally, the column address at which to stop iterating
|
||||
*/
|
||||
public function isEmpty(int $definitionOfEmptyFlags = 0): bool
|
||||
public function isEmpty(int $definitionOfEmptyFlags = 0, $startColumn = 'A', $endColumn = null): bool
|
||||
{
|
||||
$nullValueCellIsEmpty = (bool) ($definitionOfEmptyFlags & CellIterator::TREAT_NULL_VALUE_AS_EMPTY_CELL);
|
||||
$emptyStringCellIsEmpty = (bool) ($definitionOfEmptyFlags & CellIterator::TREAT_EMPTY_STRING_AS_EMPTY_CELL);
|
||||
|
||||
$cellIterator = $this->getCellIterator();
|
||||
$cellIterator = $this->getCellIterator($startColumn, $endColumn);
|
||||
$cellIterator->setIterateOnlyExistingCells(true);
|
||||
foreach ($cellIterator as $cell) {
|
||||
/** @scrutinizer ignore-call */
|
||||
|
@@ -127,7 +127,11 @@ class RowCellIterator extends CellIterator
|
||||
|
||||
return $this->cellCollection->has($cellAddress)
|
||||
? $this->cellCollection->get($cellAddress)
|
||||
: $this->worksheet->createNewCell($cellAddress);
|
||||
: (
|
||||
$this->ifNotExists === self::IF_NOT_EXISTS_CREATE_NEW
|
||||
? $this->worksheet->createNewCell($cellAddress)
|
||||
: null
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -9,7 +9,7 @@ class RowDimension extends Dimension
|
||||
/**
|
||||
* Row index.
|
||||
*
|
||||
* @var int
|
||||
* @var ?int
|
||||
*/
|
||||
private $rowIndex;
|
||||
|
||||
@@ -32,7 +32,7 @@ class RowDimension extends Dimension
|
||||
/**
|
||||
* Create a new RowDimension.
|
||||
*
|
||||
* @param int $index Numeric row index
|
||||
* @param ?int $index Numeric row index
|
||||
*/
|
||||
public function __construct($index = 0)
|
||||
{
|
||||
@@ -46,7 +46,7 @@ class RowDimension extends Dimension
|
||||
/**
|
||||
* Get Row Index.
|
||||
*/
|
||||
public function getRowIndex(): int
|
||||
public function getRowIndex(): ?int
|
||||
{
|
||||
return $this->rowIndex;
|
||||
}
|
||||
|
@@ -53,6 +53,11 @@ class RowIterator implements NativeIterator
|
||||
$this->resetStart($startRow);
|
||||
}
|
||||
|
||||
public function __destruct()
|
||||
{
|
||||
$this->subject = null; // @phpstan-ignore-line
|
||||
}
|
||||
|
||||
/**
|
||||
* (Re)Set the start row and the current row pointer.
|
||||
*
|
||||
|
@@ -148,7 +148,7 @@ class Table
|
||||
$tableName = StringHelper::strToLower($name);
|
||||
|
||||
if ($worksheet !== null && StringHelper::strToLower($this->name) !== $name) {
|
||||
$spreadsheet = $worksheet->getParent();
|
||||
$spreadsheet = $worksheet->getParentOrThrow();
|
||||
|
||||
foreach ($spreadsheet->getWorksheetIterator() as $sheet) {
|
||||
foreach ($sheet->getTableCollection() as $table) {
|
||||
@@ -170,7 +170,7 @@ class Table
|
||||
if (StringHelper::strToLower($this->name) !== StringHelper::strToLower($name)) {
|
||||
// We need to check all formula cells that might contain fully-qualified Structured References
|
||||
// that refer to this table, and update those formulae to reference the new table name
|
||||
$spreadsheet = $this->workSheet->getParent();
|
||||
$spreadsheet = $this->workSheet->getParentOrThrow();
|
||||
foreach ($spreadsheet->getWorksheetIterator() as $sheet) {
|
||||
$this->updateStructuredReferencesInCells($sheet, $name);
|
||||
}
|
||||
@@ -298,8 +298,8 @@ class Table
|
||||
}
|
||||
|
||||
[$width, $height] = Coordinate::rangeDimension($range);
|
||||
if ($width < 1 || $height < 2) {
|
||||
throw new PhpSpreadsheetException('The table range must be at least 1 column and 2 rows');
|
||||
if ($width < 1 || $height < 1) {
|
||||
throw new PhpSpreadsheetException('The table range must be at least 1 column and row');
|
||||
}
|
||||
|
||||
$this->range = $range;
|
||||
@@ -347,7 +347,7 @@ class Table
|
||||
public function setWorksheet(?Worksheet $worksheet = null): self
|
||||
{
|
||||
if ($this->name !== '' && $worksheet !== null) {
|
||||
$spreadsheet = $worksheet->getParent();
|
||||
$spreadsheet = $worksheet->getParentOrThrow();
|
||||
$tableName = StringHelper::strToUpper($this->name);
|
||||
|
||||
foreach ($spreadsheet->getWorksheetIterator() as $sheet) {
|
||||
|
@@ -205,9 +205,9 @@ class Column
|
||||
return $this;
|
||||
}
|
||||
|
||||
public static function updateStructuredReferences(?Worksheet $workSheet, ?string $oldTitle, string $newTitle): void
|
||||
public static function updateStructuredReferences(?Worksheet $workSheet, ?string $oldTitle, ?string $newTitle): void
|
||||
{
|
||||
if ($workSheet === null || $oldTitle === null || $oldTitle === '') {
|
||||
if ($workSheet === null || $oldTitle === null || $oldTitle === '' || $newTitle === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -215,7 +215,7 @@ class Column
|
||||
if (StringHelper::strToLower($oldTitle) !== StringHelper::strToLower($newTitle)) {
|
||||
// We need to check all formula cells that might contain Structured References that refer
|
||||
// to this column, and update those formulae to reference the new column text
|
||||
$spreadsheet = $workSheet->getParent();
|
||||
$spreadsheet = $workSheet->getParentOrThrow();
|
||||
foreach ($spreadsheet->getWorksheetIterator() as $sheet) {
|
||||
self::updateStructuredReferencesInCells($sheet, $oldTitle, $newTitle);
|
||||
}
|
||||
|
@@ -103,7 +103,7 @@ class Validations
|
||||
$coordinate = strtoupper($coordinate);
|
||||
// Eliminate leading equal sign
|
||||
$testCoordinate = (string) preg_replace('/^=/', '', $coordinate);
|
||||
$defined = $worksheet->getParent()->getDefinedName($testCoordinate, $worksheet);
|
||||
$defined = $worksheet->getParentOrThrow()->getDefinedName($testCoordinate, $worksheet);
|
||||
if ($defined !== null) {
|
||||
if ($defined->getWorksheet() === $worksheet && !$defined->isFormula()) {
|
||||
$coordinate = (string) preg_replace('/^=/', '', $defined->getValue());
|
||||
|
@@ -64,7 +64,7 @@ class Worksheet implements IComparable
|
||||
/**
|
||||
* Parent spreadsheet.
|
||||
*
|
||||
* @var Spreadsheet
|
||||
* @var ?Spreadsheet
|
||||
*/
|
||||
private $parent;
|
||||
|
||||
@@ -399,7 +399,6 @@ class Worksheet implements IComparable
|
||||
$this->cellCollection = null;
|
||||
}
|
||||
// detach ourself from the workbook, so that it can then delete this worksheet successfully
|
||||
// @phpstan-ignore-next-line
|
||||
$this->parent = null;
|
||||
}
|
||||
|
||||
@@ -644,13 +643,9 @@ class Worksheet implements IComparable
|
||||
*/
|
||||
public function getChartByName($chartName)
|
||||
{
|
||||
$chartCount = count($this->chartCollection);
|
||||
if ($chartCount == 0) {
|
||||
return false;
|
||||
}
|
||||
foreach ($this->chartCollection as $index => $chart) {
|
||||
if ($chart->getName() == $chartName) {
|
||||
return $this->chartCollection[$index];
|
||||
return $chart;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -760,7 +755,7 @@ class Worksheet implements IComparable
|
||||
|
||||
//The only exception is if it's a merge range value cell of a 'vertical' range (1 column wide)
|
||||
if ($isMerged && $cell->isMergeRangeValueCell()) {
|
||||
$range = $cell->getMergeRange();
|
||||
$range = (string) $cell->getMergeRange();
|
||||
$rangeBoundaries = Coordinate::rangeDimension($range);
|
||||
if ($rangeBoundaries[0] === 1) {
|
||||
$isMergedButProceed = true;
|
||||
@@ -782,7 +777,7 @@ class Worksheet implements IComparable
|
||||
// To formatted string
|
||||
$cellValue = NumberFormat::toFormattedString(
|
||||
$cell->getCalculatedValue(),
|
||||
$this->getParent()->getCellXfByIndex($cell->getXfIndex())
|
||||
(string) $this->getParentOrThrow()->getCellXfByIndex($cell->getXfIndex())
|
||||
->getNumberFormat()->getFormatCode()
|
||||
);
|
||||
|
||||
@@ -790,11 +785,11 @@ class Worksheet implements IComparable
|
||||
$autoSizes[$this->cellCollection->getCurrentColumn()] = max(
|
||||
(float) $autoSizes[$this->cellCollection->getCurrentColumn()],
|
||||
(float) Shared\Font::calculateColumnWidth(
|
||||
$this->getParent()->getCellXfByIndex($cell->getXfIndex())->getFont(),
|
||||
$this->getParentOrThrow()->getCellXfByIndex($cell->getXfIndex())->getFont(),
|
||||
$cellValue,
|
||||
$this->getParent()->getCellXfByIndex($cell->getXfIndex())
|
||||
(int) $this->getParentOrThrow()->getCellXfByIndex($cell->getXfIndex())
|
||||
->getAlignment()->getTextRotation(),
|
||||
$this->getParent()->getDefaultStyle()->getFont(),
|
||||
$this->getParentOrThrow()->getDefaultStyle()->getFont(),
|
||||
$filterAdjustment,
|
||||
$indentAdjustment
|
||||
)
|
||||
@@ -817,15 +812,25 @@ class Worksheet implements IComparable
|
||||
}
|
||||
|
||||
/**
|
||||
* Get parent.
|
||||
*
|
||||
* @return Spreadsheet
|
||||
* Get parent or null.
|
||||
*/
|
||||
public function getParent()
|
||||
public function getParent(): ?Spreadsheet
|
||||
{
|
||||
return $this->parent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get parent, throw exception if null.
|
||||
*/
|
||||
public function getParentOrThrow(): Spreadsheet
|
||||
{
|
||||
if ($this->parent !== null) {
|
||||
return $this->parent;
|
||||
}
|
||||
|
||||
throw new Exception('Sheet does not have a parent.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Re-bind parent.
|
||||
*
|
||||
@@ -1274,7 +1279,7 @@ class Worksheet implements IComparable
|
||||
if (strpos($coordinate, '!') !== false) {
|
||||
$worksheetReference = self::extractSheetTitle($coordinate, true);
|
||||
|
||||
$sheet = $this->parent->getSheetByName($worksheetReference[0]);
|
||||
$sheet = $this->getParentOrThrow()->getSheetByName($worksheetReference[0]);
|
||||
$finalCoordinate = strtoupper($worksheetReference[1]);
|
||||
|
||||
if ($sheet === null) {
|
||||
@@ -1509,12 +1514,12 @@ class Worksheet implements IComparable
|
||||
$cellCoordinate = Validations::validateCellOrCellRange($cellCoordinate);
|
||||
|
||||
// set this sheet as active
|
||||
$this->parent->setActiveSheetIndex($this->parent->getIndex($this));
|
||||
$this->getParentOrThrow()->setActiveSheetIndex($this->getParentOrThrow()->getIndex($this));
|
||||
|
||||
// set cell coordinate as active
|
||||
$this->setSelectedCells($cellCoordinate);
|
||||
|
||||
return $this->parent->getCellXfSupervisor();
|
||||
return $this->getParentOrThrow()->getCellXfSupervisor();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1666,8 +1671,8 @@ class Worksheet implements IComparable
|
||||
public function duplicateStyle(Style $style, $range)
|
||||
{
|
||||
// Add the style to the workbook if necessary
|
||||
$workbook = $this->parent;
|
||||
if ($existingStyle = $this->parent->getCellXfByHashCode($style->getHashCode())) {
|
||||
$workbook = $this->getParentOrThrow();
|
||||
if ($existingStyle = $workbook->getCellXfByHashCode($style->getHashCode())) {
|
||||
// there is already such cell Xf in our collection
|
||||
$xfIndex = $existingStyle->getIndex();
|
||||
} else {
|
||||
@@ -1899,7 +1904,7 @@ class Worksheet implements IComparable
|
||||
public function mergeCellBehaviour(Cell $cell, string $upperLeft, string $behaviour, array $leftCellValue): array
|
||||
{
|
||||
if ($cell->getCoordinate() !== $upperLeft) {
|
||||
Calculation::getInstance($cell->getWorksheet()->getParent())->flushInstance();
|
||||
Calculation::getInstance($cell->getWorksheet()->getParentOrThrow())->flushInstance();
|
||||
if ($behaviour === self::MERGE_CELL_CONTENT_MERGE) {
|
||||
$cellValue = $cell->getFormattedValue();
|
||||
if ($cellValue !== '') {
|
||||
@@ -2236,6 +2241,12 @@ class Worksheet implements IComparable
|
||||
return $tableNames;
|
||||
}
|
||||
|
||||
/** @var null|Table */
|
||||
private static $scrutinizerNullTable;
|
||||
|
||||
/** @var null|int */
|
||||
private static $scrutinizerNullInt;
|
||||
|
||||
/**
|
||||
* @param string $name the table name to search
|
||||
*
|
||||
@@ -2245,7 +2256,7 @@ class Worksheet implements IComparable
|
||||
{
|
||||
$tableIndex = $this->getTableIndexByName($name);
|
||||
|
||||
return ($tableIndex === null) ? null : $this->tableCollection[$tableIndex];
|
||||
return ($tableIndex === null) ? self::$scrutinizerNullTable : $this->tableCollection[$tableIndex];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2263,7 +2274,7 @@ class Worksheet implements IComparable
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
return self::$scrutinizerNullInt;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2495,7 +2506,7 @@ class Worksheet implements IComparable
|
||||
} elseif ($num > $highRow) {
|
||||
$num -= $numberOfRows;
|
||||
$cloneDimension = clone $rowDimension;
|
||||
$cloneDimension->setRowIndex($num);
|
||||
$cloneDimension->setRowIndex(/** @scrutinizer ignore-type */ $num);
|
||||
$holdRowDimensions[$num] = $cloneDimension;
|
||||
}
|
||||
}
|
||||
@@ -2967,9 +2978,10 @@ class Worksheet implements IComparable
|
||||
$cRef = $returnCellRef ? $col : ++$c;
|
||||
// Using getCell() will create a new cell if it doesn't already exist. We don't want that to happen
|
||||
// so we test and retrieve directly against cellCollection
|
||||
if ($this->cellCollection->has($col . $row)) {
|
||||
$cell = $this->cellCollection->get($col . $row);
|
||||
//if ($this->cellCollection->has($col . $row)) {
|
||||
if ($cell !== null) {
|
||||
// Cell exists
|
||||
$cell = $this->cellCollection->get($col . $row);
|
||||
if ($cell->getValue() !== null) {
|
||||
if ($cell->getValue() instanceof RichText) {
|
||||
$returnValue[$rRef][$cRef] = $cell->getValue()->getPlainText();
|
||||
@@ -2982,10 +2994,10 @@ class Worksheet implements IComparable
|
||||
}
|
||||
|
||||
if ($formatData) {
|
||||
$style = $this->parent->getCellXfByIndex($cell->getXfIndex());
|
||||
$style = $this->getParentOrThrow()->getCellXfByIndex($cell->getXfIndex());
|
||||
$returnValue[$rRef][$cRef] = NumberFormat::toFormattedString(
|
||||
$returnValue[$rRef][$cRef],
|
||||
($style && $style->getNumberFormat()) ? $style->getNumberFormat()->getFormatCode() : NumberFormat::FORMAT_GENERAL
|
||||
$style->getNumberFormat()->getFormatCode() ?? NumberFormat::FORMAT_GENERAL
|
||||
);
|
||||
}
|
||||
} else {
|
||||
@@ -3022,14 +3034,17 @@ class Worksheet implements IComparable
|
||||
throw new Exception('Defined Named ' . $definedName . ' is a formula, not a range or cell.');
|
||||
}
|
||||
|
||||
if ($namedRange->getLocalOnly() && $this->getHashCode() !== $namedRange->getWorksheet()->getHashCode()) {
|
||||
if ($returnNullIfInvalid) {
|
||||
return null;
|
||||
}
|
||||
if ($namedRange->getLocalOnly()) {
|
||||
$worksheet = $namedRange->getWorksheet();
|
||||
if ($worksheet === null || $this->getHashCode() !== $worksheet->getHashCode()) {
|
||||
if ($returnNullIfInvalid) {
|
||||
return null;
|
||||
}
|
||||
|
||||
throw new Exception(
|
||||
'Named range ' . $definedName . ' is not accessible from within sheet ' . $this->getTitle()
|
||||
);
|
||||
throw new Exception(
|
||||
'Named range ' . $definedName . ' is not accessible from within sheet ' . $this->getTitle()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return $namedRange;
|
||||
@@ -3049,13 +3064,18 @@ class Worksheet implements IComparable
|
||||
*/
|
||||
public function namedRangeToArray(string $definedName, $nullValue = null, $calculateFormulas = true, $formatData = true, $returnCellRef = false)
|
||||
{
|
||||
$retVal = [];
|
||||
$namedRange = $this->validateNamedRange($definedName);
|
||||
$workSheet = $namedRange->getWorksheet();
|
||||
/** @phpstan-ignore-next-line */
|
||||
$cellRange = ltrim(substr($namedRange->getValue(), strrpos($namedRange->getValue(), '!')), '!');
|
||||
$cellRange = str_replace('$', '', $cellRange);
|
||||
if ($namedRange !== null) {
|
||||
$cellRange = ltrim(substr($namedRange->getValue(), (int) strrpos($namedRange->getValue(), '!')), '!');
|
||||
$cellRange = str_replace('$', '', $cellRange);
|
||||
$workSheet = $namedRange->getWorksheet();
|
||||
if ($workSheet !== null) {
|
||||
$retVal = $workSheet->rangeToArray($cellRange, $nullValue, $calculateFormulas, $formatData, $returnCellRef);
|
||||
}
|
||||
}
|
||||
|
||||
return $workSheet->rangeToArray($cellRange, $nullValue, $calculateFormulas, $formatData, $returnCellRef);
|
||||
return $retVal;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3516,16 +3536,16 @@ class Worksheet implements IComparable
|
||||
|
||||
// We use the same code that setTitle to find a valid codeName else not using a space (Excel don't like) but a '_'
|
||||
|
||||
if ($this->getParent()) {
|
||||
if ($this->parent !== null) {
|
||||
// Is there already such sheet name?
|
||||
if ($this->getParent()->sheetCodeNameExists($codeName)) {
|
||||
if ($this->parent->sheetCodeNameExists($codeName)) {
|
||||
// Use name, but append with lowest possible integer
|
||||
|
||||
if (Shared\StringHelper::countCharacters($codeName) > 29) {
|
||||
$codeName = Shared\StringHelper::substring($codeName, 0, 29);
|
||||
}
|
||||
$i = 1;
|
||||
while ($this->getParent()->sheetCodeNameExists($codeName . '_' . $i)) {
|
||||
while ($this->getParentOrThrow()->sheetCodeNameExists($codeName . '_' . $i)) {
|
||||
++$i;
|
||||
if ($i == 10) {
|
||||
if (Shared\StringHelper::countCharacters($codeName) > 28) {
|
||||
|
@@ -803,7 +803,12 @@ class Html extends BaseWriter
|
||||
private function buildCssPerSheet(Worksheet $sheet, array &$css): void
|
||||
{
|
||||
// Calculate hash code
|
||||
$sheetIndex = $sheet->getParent()->getIndex($sheet);
|
||||
$sheetIndex = $sheet->getParentOrThrow()->getIndex($sheet);
|
||||
$setup = $sheet->getPageSetup();
|
||||
if ($setup->getFitToPage() && $setup->getFitToHeight() === 1) {
|
||||
$css["table.sheet$sheetIndex"]['page-break-inside'] = 'avoid';
|
||||
$css["table.sheet$sheetIndex"]['break-inside'] = 'avoid';
|
||||
}
|
||||
|
||||
// Build styles
|
||||
// Calculate column widths
|
||||
@@ -1139,7 +1144,7 @@ class Html extends BaseWriter
|
||||
*/
|
||||
private function generateTableHeader(Worksheet $worksheet, $showid = true)
|
||||
{
|
||||
$sheetIndex = $worksheet->getParent()->getIndex($worksheet);
|
||||
$sheetIndex = $worksheet->getParentOrThrow()->getIndex($worksheet);
|
||||
|
||||
// Construct HTML
|
||||
$html = '';
|
||||
@@ -1284,7 +1289,7 @@ class Html extends BaseWriter
|
||||
$this->generateRowCellDataValueRich($cell, $cellData);
|
||||
} else {
|
||||
$origData = $this->preCalculateFormulas ? $cell->getCalculatedValue() : $cell->getValue();
|
||||
$formatCode = $worksheet->getParent()->getCellXfByIndex($cell->getXfIndex())->getNumberFormat()->getFormatCode();
|
||||
$formatCode = $worksheet->getParentOrThrow()->getCellXfByIndex($cell->getXfIndex())->getNumberFormat()->getFormatCode();
|
||||
|
||||
$cellData = NumberFormat::toFormattedString(
|
||||
$origData ?? '',
|
||||
@@ -1295,9 +1300,9 @@ class Html extends BaseWriter
|
||||
if ($cellData === $origData) {
|
||||
$cellData = htmlspecialchars($cellData, Settings::htmlEntityFlags());
|
||||
}
|
||||
if ($worksheet->getParent()->getCellXfByIndex($cell->getXfIndex())->getFont()->getSuperscript()) {
|
||||
if ($worksheet->getParentOrThrow()->getCellXfByIndex($cell->getXfIndex())->getFont()->getSuperscript()) {
|
||||
$cellData = '<sup>' . $cellData . '</sup>';
|
||||
} elseif ($worksheet->getParent()->getCellXfByIndex($cell->getXfIndex())->getFont()->getSubscript()) {
|
||||
} elseif ($worksheet->getParentOrThrow()->getCellXfByIndex($cell->getXfIndex())->getFont()->getSubscript()) {
|
||||
$cellData = '<sub>' . $cellData . '</sub>';
|
||||
}
|
||||
}
|
||||
@@ -1342,7 +1347,7 @@ class Html extends BaseWriter
|
||||
}
|
||||
|
||||
// General horizontal alignment: Actual horizontal alignment depends on dataType
|
||||
$sharedStyle = $worksheet->getParent()->getCellXfByIndex($cell->getXfIndex());
|
||||
$sharedStyle = $worksheet->getParentOrThrow()->getCellXfByIndex($cell->getXfIndex());
|
||||
if (
|
||||
$sharedStyle->getAlignment()->getHorizontal() == Alignment::HORIZONTAL_GENERAL
|
||||
&& isset($this->cssStyles['.' . $cell->getDataType()]['text-align'])
|
||||
@@ -1449,7 +1454,7 @@ class Html extends BaseWriter
|
||||
private function generateRow(Worksheet $worksheet, array $values, $row, $cellType)
|
||||
{
|
||||
// Sheet index
|
||||
$sheetIndex = $worksheet->getParent()->getIndex($worksheet);
|
||||
$sheetIndex = $worksheet->getParentOrThrow()->getIndex($worksheet);
|
||||
$html = $this->generateRowStart($worksheet, $sheetIndex, $row);
|
||||
$generateDiv = $this->isMPdf && $worksheet->getRowDimension($row + 1)->getVisible() === false;
|
||||
if ($generateDiv) {
|
||||
@@ -1470,14 +1475,14 @@ class Html extends BaseWriter
|
||||
}
|
||||
|
||||
// Should the cell be written or is it swallowed by a rowspan or colspan?
|
||||
$writeCell = !(isset($this->isSpannedCell[$worksheet->getParent()->getIndex($worksheet)][$row + 1][$colNum])
|
||||
&& $this->isSpannedCell[$worksheet->getParent()->getIndex($worksheet)][$row + 1][$colNum]);
|
||||
$writeCell = !(isset($this->isSpannedCell[$worksheet->getParentOrThrow()->getIndex($worksheet)][$row + 1][$colNum])
|
||||
&& $this->isSpannedCell[$worksheet->getParentOrThrow()->getIndex($worksheet)][$row + 1][$colNum]);
|
||||
|
||||
// Colspan and Rowspan
|
||||
$colSpan = 1;
|
||||
$rowSpan = 1;
|
||||
if (isset($this->isBaseCell[$worksheet->getParent()->getIndex($worksheet)][$row + 1][$colNum])) {
|
||||
$spans = $this->isBaseCell[$worksheet->getParent()->getIndex($worksheet)][$row + 1][$colNum];
|
||||
if (isset($this->isBaseCell[$worksheet->getParentOrThrow()->getIndex($worksheet)][$row + 1][$colNum])) {
|
||||
$spans = $this->isBaseCell[$worksheet->getParentOrThrow()->getIndex($worksheet)][$row + 1][$colNum];
|
||||
$rowSpan = $spans['rowspan'];
|
||||
$colSpan = $spans['colspan'];
|
||||
|
||||
|
@@ -245,7 +245,7 @@ class Xls extends BaseWriter
|
||||
|
||||
foreach ($this->spreadsheet->getAllsheets() as $sheet) {
|
||||
// sheet index
|
||||
$sheetIndex = $sheet->getParent()->getIndex($sheet);
|
||||
$sheetIndex = $sheet->getParentOrThrow()->getIndex($sheet);
|
||||
|
||||
// check if there are any shapes for this sheet
|
||||
$filterRange = $sheet->getAutoFilter()->getRange();
|
||||
@@ -260,7 +260,7 @@ class Xls extends BaseWriter
|
||||
$dgContainer = new DgContainer();
|
||||
|
||||
// set the drawing index (we use sheet index + 1)
|
||||
$dgId = $sheet->getParent()->getIndex($sheet) + 1;
|
||||
$dgId = $sheet->getParentOrThrow()->getIndex($sheet) + 1;
|
||||
$dgContainer->setDgId($dgId);
|
||||
$escher->setDgContainer($dgContainer);
|
||||
|
||||
@@ -272,7 +272,7 @@ class Xls extends BaseWriter
|
||||
$spContainer = new SpContainer();
|
||||
$spContainer->setSpgr(true);
|
||||
$spContainer->setSpType(0);
|
||||
$spContainer->setSpId(($sheet->getParent()->getIndex($sheet) + 1) << 10);
|
||||
$spContainer->setSpId(($sheet->getParentOrThrow()->getIndex($sheet) + 1) << 10);
|
||||
$spgrContainer->addChild($spContainer);
|
||||
|
||||
// add the shapes
|
||||
@@ -294,7 +294,7 @@ class Xls extends BaseWriter
|
||||
|
||||
// set the shape index (we combine 1-based sheet index and $countShapes to create unique shape index)
|
||||
$reducedSpId = $countShapes[$sheetIndex];
|
||||
$spId = $reducedSpId | ($sheet->getParent()->getIndex($sheet) + 1) << 10;
|
||||
$spId = $reducedSpId | ($sheet->getParentOrThrow()->getIndex($sheet) + 1) << 10;
|
||||
$spContainer->setSpId($spId);
|
||||
|
||||
// keep track of last reducedSpId
|
||||
@@ -351,7 +351,7 @@ class Xls extends BaseWriter
|
||||
|
||||
// set the shape index (we combine 1-based sheet index and $countShapes to create unique shape index)
|
||||
$reducedSpId = $countShapes[$sheetIndex];
|
||||
$spId = $reducedSpId | ($sheet->getParent()->getIndex($sheet) + 1) << 10;
|
||||
$spId = $reducedSpId | ($sheet->getParentOrThrow()->getIndex($sheet) + 1) << 10;
|
||||
$spContainer->setSpId($spId);
|
||||
|
||||
// keep track of last reducedSpId
|
||||
|
@@ -603,12 +603,9 @@ class Workbook extends BIFFwriter
|
||||
}
|
||||
|
||||
if ($definedName->getLocalOnly()) {
|
||||
/**
|
||||
* local scope.
|
||||
*
|
||||
* @phpstan-ignore-next-line
|
||||
*/
|
||||
$scope = $this->spreadsheet->getIndex($definedName->getScope()) + 1;
|
||||
// local scope
|
||||
$scopeWs = $definedName->getScope();
|
||||
$scope = ($scopeWs === null) ? 0 : ($this->spreadsheet->getIndex($scopeWs) + 1);
|
||||
} else {
|
||||
// global scope
|
||||
$scope = 0;
|
||||
|
@@ -273,7 +273,7 @@ class Worksheet extends BIFFwriter
|
||||
$this->lastColumnIndex = 255;
|
||||
}
|
||||
|
||||
$this->countCellStyleXfs = count($phpSheet->getParent()->getCellStyleXfCollection());
|
||||
$this->countCellStyleXfs = count($phpSheet->getParentOrThrow()->getCellStyleXfCollection());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -288,7 +288,7 @@ class Worksheet extends BIFFwriter
|
||||
|
||||
// Storing selected cells and active sheet because it changes while parsing cells with formulas.
|
||||
$selectedCells = $this->phpSheet->getSelectedCells();
|
||||
$activeSheetIndex = $this->phpSheet->getParent()->getActiveSheetIndex();
|
||||
$activeSheetIndex = $this->phpSheet->getParentOrThrow()->getActiveSheetIndex();
|
||||
|
||||
// Write BOF record
|
||||
$this->storeBof(0x0010);
|
||||
@@ -307,7 +307,7 @@ class Worksheet extends BIFFwriter
|
||||
|
||||
// Column dimensions
|
||||
if (($defaultWidth = $phpSheet->getDefaultColumnDimension()->getWidth()) < 0) {
|
||||
$defaultWidth = \PhpOffice\PhpSpreadsheet\Shared\Font::getDefaultColumnWidthByFont($phpSheet->getParent()->getDefaultStyle()->getFont());
|
||||
$defaultWidth = \PhpOffice\PhpSpreadsheet\Shared\Font::getDefaultColumnWidthByFont($phpSheet->getParentOrThrow()->getDefaultStyle()->getFont());
|
||||
}
|
||||
|
||||
$columnDimensions = $phpSheet->getColumnDimensions();
|
||||
@@ -498,7 +498,7 @@ class Worksheet extends BIFFwriter
|
||||
$this->writeMsoDrawing();
|
||||
|
||||
// Restoring active sheet.
|
||||
$this->phpSheet->getParent()->setActiveSheetIndex($activeSheetIndex);
|
||||
$this->phpSheet->getParentOrThrow()->setActiveSheetIndex($activeSheetIndex);
|
||||
|
||||
// Write WINDOW2 record
|
||||
$this->writeWindow2();
|
||||
@@ -1255,7 +1255,7 @@ class Worksheet extends BIFFwriter
|
||||
$fDspGuts = $this->outlineOn; // 7
|
||||
$fFrozenNoSplit = 0; // 0 - bit
|
||||
// no support in PhpSpreadsheet for selected sheet, therefore sheet is only selected if it is the active sheet
|
||||
$fSelected = ($this->phpSheet === $this->phpSheet->getParent()->getActiveSheet()) ? 1 : 0;
|
||||
$fSelected = ($this->phpSheet === $this->phpSheet->getParentOrThrow()->getActiveSheet()) ? 1 : 0;
|
||||
$fPageBreakPreview = $this->phpSheet->getSheetView()->getView() === SheetView::SHEETVIEW_PAGE_BREAK_PREVIEW;
|
||||
|
||||
$grbit = $fDspFmla;
|
||||
@@ -1677,7 +1677,7 @@ class Worksheet extends BIFFwriter
|
||||
|
||||
// Order of printing pages
|
||||
$fLeftToRight = $this->phpSheet->getPageSetup()->getPageOrder() === PageSetup::PAGEORDER_DOWN_THEN_OVER
|
||||
? 0x1 : 0x0;
|
||||
? 0x0 : 0x1;
|
||||
// Page orientation
|
||||
$fLandscape = ($this->phpSheet->getPageSetup()->getOrientation() == PageSetup::ORIENTATION_LANDSCAPE)
|
||||
? 0x0 : 0x1;
|
||||
|
@@ -455,14 +455,17 @@ class Xlsx extends BaseWriter
|
||||
}
|
||||
|
||||
// Add comment relationship parts
|
||||
if (count($this->spreadSheet->getSheet($i)->getComments()) > 0) {
|
||||
$legacy = $unparsedLoadedData['sheets'][$this->spreadSheet->getSheet($i)->getCodeName()]['legacyDrawing'] ?? null;
|
||||
if (count($this->spreadSheet->getSheet($i)->getComments()) > 0 || $legacy !== null) {
|
||||
// VML Comments relationships
|
||||
$zipContent['xl/drawings/_rels/vmlDrawing' . ($i + 1) . '.vml.rels'] = $this->getWriterPartRels()->writeVMLDrawingRelationships($this->spreadSheet->getSheet($i));
|
||||
|
||||
// VML Comments
|
||||
$zipContent['xl/drawings/vmlDrawing' . ($i + 1) . '.vml'] = $this->getWriterPartComments()->writeVMLComments($this->spreadSheet->getSheet($i));
|
||||
$zipContent['xl/drawings/vmlDrawing' . ($i + 1) . '.vml'] = $legacy ?? $this->getWriterPartComments()->writeVMLComments($this->spreadSheet->getSheet($i));
|
||||
}
|
||||
|
||||
// Comments
|
||||
// Comments
|
||||
if (count($this->spreadSheet->getSheet($i)->getComments()) > 0) {
|
||||
$zipContent['xl/comments' . ($i + 1) . '.xml'] = $this->getWriterPartComments()->writeComments($this->spreadSheet->getSheet($i));
|
||||
|
||||
// Media
|
||||
@@ -477,7 +480,9 @@ class Xlsx extends BaseWriter
|
||||
// Add unparsed relationship parts
|
||||
if (isset($unparsedLoadedData['sheets'][$sheetCodeName]['vmlDrawings'])) {
|
||||
foreach ($unparsedLoadedData['sheets'][$sheetCodeName]['vmlDrawings'] as $vmlDrawing) {
|
||||
$zipContent[$vmlDrawing['filePath']] = $vmlDrawing['content'];
|
||||
if (!isset($zipContent[$vmlDrawing['filePath']])) {
|
||||
$zipContent[$vmlDrawing['filePath']] = $vmlDrawing['content'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -1041,11 +1041,12 @@ class Chart extends WriterPart
|
||||
$objWriter->startElement('c:ser');
|
||||
|
||||
$objWriter->startElement('c:idx');
|
||||
$objWriter->writeAttribute('val', (string) ($this->seriesIndex + $plotSeriesIdx));
|
||||
$adder = array_key_exists(0, $plotSeriesOrder) ? $this->seriesIndex : 0;
|
||||
$objWriter->writeAttribute('val', (string) ($adder + $plotSeriesIdx));
|
||||
$objWriter->endElement();
|
||||
|
||||
$objWriter->startElement('c:order');
|
||||
$objWriter->writeAttribute('val', (string) ($this->seriesIndex + $plotSeriesRef));
|
||||
$objWriter->writeAttribute('val', (string) ($adder + $plotSeriesRef));
|
||||
$objWriter->endElement();
|
||||
|
||||
$plotLabel = $plotGroup->getPlotLabelByIndex($plotSeriesIdx);
|
||||
|
@@ -72,7 +72,7 @@ class DefinedNames
|
||||
$local = -1;
|
||||
if ($definedName->getLocalOnly() && $definedName->getScope() !== null) {
|
||||
try {
|
||||
$local = $definedName->getScope()->getParent()->getIndex($definedName->getScope());
|
||||
$local = $definedName->getScope()->getParentOrThrow()->getIndex($definedName->getScope());
|
||||
} catch (Exception $e) {
|
||||
// See issue 2266 - deleting sheet which contains
|
||||
// defined names will cause Exception above.
|
||||
|
@@ -67,7 +67,7 @@ class Drawing extends WriterPart
|
||||
}
|
||||
|
||||
// unparsed AlternateContent
|
||||
$unparsedLoadedData = $worksheet->getParent()->getUnparsedLoadedData();
|
||||
$unparsedLoadedData = $worksheet->getParentOrThrow()->getUnparsedLoadedData();
|
||||
if (isset($unparsedLoadedData['sheets'][$worksheet->getCodeName()]['drawingAlternateContents'])) {
|
||||
foreach ($unparsedLoadedData['sheets'][$worksheet->getCodeName()]['drawingAlternateContents'] as $drawingAlternateContent) {
|
||||
$objWriter->writeRaw($drawingAlternateContent);
|
||||
|
@@ -188,7 +188,7 @@ class Rels extends WriterPart
|
||||
|
||||
// Write drawing relationships?
|
||||
$drawingOriginalIds = [];
|
||||
$unparsedLoadedData = $worksheet->getParent()->getUnparsedLoadedData();
|
||||
$unparsedLoadedData = $worksheet->getParentOrThrow()->getUnparsedLoadedData();
|
||||
if (isset($unparsedLoadedData['sheets'][$worksheet->getCodeName()]['drawingOriginalIds'])) {
|
||||
$drawingOriginalIds = $unparsedLoadedData['sheets'][$worksheet->getCodeName()]['drawingOriginalIds'];
|
||||
}
|
||||
@@ -239,14 +239,16 @@ class Rels extends WriterPart
|
||||
|
||||
// Write comments relationship?
|
||||
$i = 1;
|
||||
if (count($worksheet->getComments()) > 0) {
|
||||
if (count($worksheet->getComments()) > 0 || isset($unparsedLoadedData['sheets'][$worksheet->getCodeName()]['legacyDrawing'])) {
|
||||
$this->writeRelationship(
|
||||
$objWriter,
|
||||
'_comments_vml' . $i,
|
||||
Namespaces::VML,
|
||||
'../drawings/vmlDrawing' . $worksheetId . '.vml'
|
||||
);
|
||||
}
|
||||
|
||||
if (count($worksheet->getComments()) > 0) {
|
||||
$this->writeRelationship(
|
||||
$objWriter,
|
||||
'_comments' . $i,
|
||||
@@ -288,7 +290,7 @@ class Rels extends WriterPart
|
||||
|
||||
private function writeUnparsedRelationship(\PhpOffice\PhpSpreadsheet\Worksheet\Worksheet $worksheet, XMLWriter $objWriter, string $relationship, string $type): void
|
||||
{
|
||||
$unparsedLoadedData = $worksheet->getParent()->getUnparsedLoadedData();
|
||||
$unparsedLoadedData = $worksheet->getParentOrThrow()->getUnparsedLoadedData();
|
||||
if (!isset($unparsedLoadedData['sheets'][$worksheet->getCodeName()][$relationship])) {
|
||||
return;
|
||||
}
|
||||
|
@@ -138,7 +138,7 @@ class Worksheet extends WriterPart
|
||||
{
|
||||
// sheetPr
|
||||
$objWriter->startElement('sheetPr');
|
||||
if ($worksheet->getParent()->hasMacros()) {
|
||||
if ($worksheet->getParentOrThrow()->hasMacros()) {
|
||||
//if the workbook have macros, we need to have codeName for the sheet
|
||||
if (!$worksheet->hasCodeName()) {
|
||||
$worksheet->setCodeName($worksheet->getTitle());
|
||||
@@ -969,7 +969,7 @@ class Worksheet extends WriterPart
|
||||
}
|
||||
$objWriter->writeAttribute('pageOrder', $worksheet->getPageSetup()->getPageOrder());
|
||||
|
||||
$getUnparsedLoadedData = $worksheet->getParent()->getUnparsedLoadedData();
|
||||
$getUnparsedLoadedData = $worksheet->getParentOrThrow()->getUnparsedLoadedData();
|
||||
if (isset($getUnparsedLoadedData['sheets'][$worksheet->getCodeName()]['pageSetupRelId'])) {
|
||||
$objWriter->writeAttribute('r:id', $getUnparsedLoadedData['sheets'][$worksheet->getCodeName()]['pageSetupRelId']);
|
||||
}
|
||||
@@ -1305,7 +1305,7 @@ class Worksheet extends WriterPart
|
||||
*/
|
||||
private function writeDrawings(XMLWriter $objWriter, PhpspreadsheetWorksheet $worksheet, $includeCharts = false): void
|
||||
{
|
||||
$unparsedLoadedData = $worksheet->getParent()->getUnparsedLoadedData();
|
||||
$unparsedLoadedData = $worksheet->getParentOrThrow()->getUnparsedLoadedData();
|
||||
$hasUnparsedDrawing = isset($unparsedLoadedData['sheets'][$worksheet->getCodeName()]['drawingOriginalIds']);
|
||||
$chartCount = ($includeCharts) ? $worksheet->getChartCollection()->count() : 0;
|
||||
if ($chartCount == 0 && $worksheet->getDrawingCollection()->count() == 0 && !$hasUnparsedDrawing) {
|
||||
@@ -1333,7 +1333,8 @@ class Worksheet extends WriterPart
|
||||
private function writeLegacyDrawing(XMLWriter $objWriter, PhpspreadsheetWorksheet $worksheet): void
|
||||
{
|
||||
// If sheet contains comments, add the relationships
|
||||
if (count($worksheet->getComments()) > 0) {
|
||||
$unparsedLoadedData = $worksheet->getParentOrThrow()->getUnparsedLoadedData();
|
||||
if (count($worksheet->getComments()) > 0 || isset($unparsedLoadedData['sheets'][$worksheet->getCodeName()]['legacyDrawing'])) {
|
||||
$objWriter->startElement('legacyDrawing');
|
||||
$objWriter->writeAttribute('r:id', 'rId_comments_vml1');
|
||||
$objWriter->endElement();
|
||||
@@ -1355,11 +1356,11 @@ class Worksheet extends WriterPart
|
||||
|
||||
private function writeAlternateContent(XMLWriter $objWriter, PhpspreadsheetWorksheet $worksheet): void
|
||||
{
|
||||
if (empty($worksheet->getParent()->getUnparsedLoadedData()['sheets'][$worksheet->getCodeName()]['AlternateContents'])) {
|
||||
if (empty($worksheet->getParentOrThrow()->getUnparsedLoadedData()['sheets'][$worksheet->getCodeName()]['AlternateContents'])) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($worksheet->getParent()->getUnparsedLoadedData()['sheets'][$worksheet->getCodeName()]['AlternateContents'] as $alternateContent) {
|
||||
foreach ($worksheet->getParentOrThrow()->getUnparsedLoadedData()['sheets'][$worksheet->getCodeName()]['AlternateContents'] as $alternateContent) {
|
||||
$objWriter->writeRaw($alternateContent);
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user