validation-bugsnag-email

This commit is contained in:
RafficMohammed
2023-01-31 13:17:59 +05:30
parent 2ec836b447
commit 9dd3f53910
769 changed files with 20242 additions and 14060 deletions

View File

@@ -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

View File

@@ -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.).

View File

@@ -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

View File

@@ -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'][] = [

View File

@@ -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;
}
}

View File

@@ -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

View File

@@ -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.

View File

@@ -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;
}
}

View File

@@ -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;

View File

@@ -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) {

View File

@@ -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':

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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.
*

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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();

View File

@@ -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;
}

View File

@@ -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;

View File

@@ -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
*/

View File

@@ -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) {

View File

@@ -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);

View File

@@ -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));

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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();

View File

@@ -4,6 +4,7 @@ namespace PhpOffice\PhpSpreadsheet\Calculation\Internal;
class MakeMatrix
{
/** @param array $args */
public static function make(...$args): array
{
return $args;

View File

@@ -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);
}
}

View File

@@ -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 (

View File

@@ -66,7 +66,7 @@ class Helpers
}
$worksheet = ($sheetName !== '')
? $cell->getWorksheet()->getParent()->getSheetByName($sheetName)
? $cell->getWorksheet()->getParentOrThrow()->getSheetByName($sheetName)
: $cell->getWorksheet();
return [$cellAddress, $worksheet, $sheetName];

View File

@@ -108,7 +108,7 @@ class Offset
}
$worksheet = ($sheetName !== '')
? $cell->getWorksheet()->getParent()->getSheetByName($sheetName)
? $cell->getWorksheet()->getParentOrThrow()->getSheetByName($sheetName)
: $cell->getWorksheet();
return [$cellAddress, $worksheet];

View File

@@ -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 = [])
{

View File

@@ -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);
}
}

View File

@@ -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();
}
}

View File

@@ -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
*/

View File

@@ -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
*

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;
/**

View File

@@ -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);

View File

@@ -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

View File

@@ -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;

View File

@@ -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

View File

@@ -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;
}
}

View File

@@ -11,8 +11,6 @@ class StudentT
{
use ArrayEnabled;
private const MAX_ITERATIONS = 256;
/**
* TDIST.
*

View File

@@ -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)) {

View File

@@ -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);

View File

@@ -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);

View File

@@ -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,

View File

@@ -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);
}

View File

@@ -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)) {

View File

@@ -8,6 +8,8 @@ interface AddressRange
public const MAX_COLUMN = 'XFD';
public const MAX_COLUMN_INT = 16384;
/**
* @return mixed
*/

View File

@@ -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)) {

View File

@@ -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];

View File

@@ -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;
}

View File

@@ -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);
}
/**

View File

@@ -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.

View File

@@ -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);
}
}

View File

@@ -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
*

View File

@@ -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);
}
}
}

View File

@@ -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);

View File

@@ -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 {

View File

@@ -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.

View File

@@ -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

View File

@@ -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);
}
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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();

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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);

View File

@@ -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.

View File

@@ -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 */

View File

@@ -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
);
}
/**

View File

@@ -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 ?? '');
}
/**

View File

@@ -220,7 +220,7 @@ class Shadow implements IComparable
*
* @return $this
*/
public function setColor(?Color $color = null)
public function setColor(Color $color)
{
$this->color = $color;

View File

@@ -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])) {

View File

@@ -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 */

View File

@@ -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
);
}
/**

View File

@@ -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;
}

View File

@@ -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.
*

View File

@@ -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) {

View File

@@ -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);
}

View File

@@ -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());

View File

@@ -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) {

View File

@@ -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'];

View File

@@ -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

View File

@@ -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;

View File

@@ -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;

View File

@@ -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'];
}
}
}

View File

@@ -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);

View File

@@ -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.

View File

@@ -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);

View File

@@ -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;
}

View File

@@ -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);
}
}